Agenda
- A brief review of non-Gaussian models.
- The Motivations for Mixed Effects Models
- How to fit Mixed Effects Models.
library(tidyverse)
library(broom)
library(ggplot2)
library(lme4)
library(multivariate2017)
Brief review of non-gaussian models
We’re going to briefly cover non-Gaussian models, in order to avoid the symptom of “when you have a hammer, everything looks like a nail.”
When not working with continuous data, the most common kind of data you’re likely to work with is count data of some kind. This count data can have two different qualities.
- Rate - How often did something happen at all, or per some unit of time.
- Proportion - How often did something happen out of all possible instances it could have happened.
These two kinds of data call for different generalized linear models.
- Rate - use a Poisson model.
- Proportion - use a Logistic model.
We’ll walk through these briefly using the example of filled pauses.
Filled Pauses
Sometimes when speaking, speakers experience so-called “disfluencies.” Among disfluencies, filled pauses have been treated as being a special sort. In American English Writing these are usually written out as <um> and <uh>, and in British English Writing they’re usually written out as <erm> and <er>. While the exact quality of the vowel can differ between varieties and dialects, we’re going to focus on just the alternation between whether it ends in an /m/ or us just an unstressed vowel.
The data here is drawn from naturalistic sociolinguistic interviews carried out in Philadelphia. You can access the data yourself if you run
library(devtools)
install_github("jofrhwld/UhUm")
library(UhUm)
Poisson regression
For every speaker, we’ll first model how often they used filled pauses at all. This will involve counting up all of their filled pauses, as well as how many total words they spoke. It’s necessary to count up how many total words were spoken, because not all interviews were the same length, meaning speakers had differential opportunity to use filled pauses. The duration of the interview is the exposure variable.
fp_count <- um_PNC %>%
mutate(age0 = (age-20)/10)%>%
group_by(idstring,
age0,
sex,
nwords) %>%
count()
We’ll look at the effect of age and sex on the overall rate of filled pauses like so:

fp_model <- glm(n ~ age0 * sex,
offset = log(nwords),
data = fp_count,
family = poisson)
summary(fp_model)
Call:
glm(formula = n ~ age0 * sex, family = poisson, data = fp_count,
offset = log(nwords))
Deviance Residuals:
Min 1Q Median 3Q Max
-21.109 -3.796 -1.105 2.506 25.009
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -4.250434 0.013831 -307.31 < 2e-16 ***
age0 0.050502 0.004088 12.36 < 2e-16 ***
sexm 0.166064 0.019841 8.37 < 2e-16 ***
age0:sexm 0.030427 0.005966 5.10 3.39e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for poisson family taken to be 1)
Null deviance: 10828.6 on 394 degrees of freedom
Residual deviance: 9985.3 on 391 degrees of freedom
AIC: 12181
Number of Fisher Scoring iterations: 5
Without exactly understanding what the exact numbers mean, we can walk away with this understanding:
- the large negative intercept means that filled pauses are relatively rare (but we should compare this to other words to be sure)/
- The positive age effect means that as people get older, their rate of filled pauses increases.
- The positive sex effect means that men use filled pauses a bit more often than women.
- The positive interaction effect means that the age effect is a quite a bit stronger for men.
The specific estimates for the model are:
# Filled pauses per 1000 words at age0==0, sex==f
exp(-4.250434) * 1000
[1] 14.25804
# Filled pauses per 1000 words age0==2, sex==f
exp(-4.250434 + (2*0.050502)) * 1000
[1] 15.7734
# Filled pauses per 1000 words at age0==0, sex==m
exp(-4.250434 + 0.166064) * 1000
[1] 16.83374
# Filled pauses per 1000 words at age0==2, sex==m
exp(-4.250434 + 0.166064 + (2 * (0.050502 + 0.030427 ))) * 1000
[1] 19.79132
Logistic regression
If we’re interested not just in their overall rate of filled pause use, but rather when they used a filled pause, which one did they use, we would fit a logistic regression.
um_df <- um_PNC %>%
mutate(is_um = (word == "UM") * 1,
age0 = (age-20)/10)
um_proportion <- um_df %>%
group_by(idstring, age0, sex)%>%
summarise(um_prop = mean(is_um))

um_model <- glm(is_um~age0*sex,
data = um_df,
family = binomial)
summary(um_model)
Call:
glm(formula = is_um ~ age0 * sex, family = binomial, data = um_df)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.4803 -0.7055 -0.4725 -0.1821 2.9013
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.19017 0.02852 6.669 2.58e-11 ***
age0 -0.41545 0.01018 -40.806 < 2e-16 ***
sexm -0.99217 0.04599 -21.571 < 2e-16 ***
age0:sexm -0.09844 0.01988 -4.953 7.32e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 27657 on 25522 degrees of freedom
Residual deviance: 23366 on 25519 degrees of freedom
AIC: 23374
Number of Fisher Scoring iterations: 5
The rationale behind LMEs
The original reasoning behind moving to linear mixed effects modelling has a lot to do with sophisticated statistical reasoning which I’ll just briefly discuss. Let’s return to our ayT data. Recall, this is a collection of /ay/ pronunciations gathered from recorded interviews with 326 speakers from Philadelphia. Today, we’ll be looking at the effect of the vowels’ duration on the normalized F1.
To start off, we’ll be transforming the duration predictor. Specifically, I’ll be log2 transforming it, then subtracting the median. In mathematical notation that’s
\[
\text{dur_c} = \log_2(\text{duration})-median(\log_2(\text{duration}))
\]
The reason I’m doing this transformation is because duration values tend to have a long, rightward tail. Log transforming the duration helps make the distribution a bit more symmetrical.
A log transform of any base would do the job, actually (e.g. natural log, or log() or log10()). I chose log2 because of the effect it has on interpreting the slope. Every increase of 1 on the log2 scale corresponds to doubling the duration. So, instead of saying “the effect of log(duration) is X”, we can say “the effect of doubling duration is X”.
It’s important to note that I’m also only doing this because I don’t have a specific theory about why the effect of duration should be additive. Some information processing theories have specific predictions about additive effects of reaction times, and in those cases you maybe shouldn’t log RTs (Lo & Andrews 2015).
# filter() gets just the subset of the data that is pre-voiceless
# I log2 and center the duration in two steps inside mutate().
ayT <- ay %>%
filter(plt_vclass == "ay0") %>%
mutate(log2_dur = log2(dur),
dur_c = log2_dur - median(log2_dur),
dob = year-age,
decade = (dob-1900)/10)
ayT %>%
ggplot(aes(dur_c, F1_n))+
geom_point(alpha = 0.05)+
stat_smooth(method = 'lm', color = 'red')+
theme_bw()

You may not even be able to tell that the regression line has has a confidence interval because it is narrower than the width of the line! That’s because the model has low uncertainty about the slope:
summary(lm(F1_n ~ dur_c, data = ayT))
Call:
lm(formula = F1_n ~ dur_c, data = ayT)
Residuals:
Min 1Q Median 3Q Max
-2.4731 -0.3900 -0.0324 0.3498 5.2217
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.487737 0.004161 117.22 <2e-16 ***
dur_c 0.435710 0.007068 61.65 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.578 on 19340 degrees of freedom
Multiple R-squared: 0.1642, Adjusted R-squared: 0.1642
F-statistic: 3800 on 1 and 19340 DF, p-value: < 2.2e-16
But in an important sense, this model is overly confident. It thinks it’s working with 19,342 independent observations. As if 19,342 different people walked up to a microphone and said ay. But that is exactly not what happened here. Instead, a smaller number of speakers (326) had many tokens of ay, and not always the same number of tokens each.
To make the example more extreme, let’s imagine we had data from only two speakers, one who produced very many tokens, and who who produced relatively few.

Based on just these two speakers, it would be hard to say what the real effect of duration on F1 is. One speaker has a fairly positive slope, and the other has a fairly negative slope. However, if you fit a model with just these two speakers’ data in the model, the estimated slope would be be dominated by the speaker with a lot of data, and almost none given to the speaker with very little.
Call:
lm(formula = F1_n ~ dur_c, data = .)
Residuals:
Min 1Q Median 3Q Max
-1.48608 -0.57665 -0.00132 0.63510 1.62271
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.1836 0.1532 7.726 1.61e-08 ***
dur_c 0.8775 0.2800 3.134 0.00393 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.85 on 29 degrees of freedom
Multiple R-squared: 0.253, Adjusted R-squared: 0.2272
F-statistic: 9.822 on 1 and 29 DF, p-value: 0.003926
However, this is not ideal, since we should give a bit more weight to the fact that at least one speaker has a weaker effect, even if they have less data. An even more perverse situation could arise if there’s a strong correlation between a the speaker and their intercept. For example, in these figures it looks like the relationship between duration and F1 is positive, but it’s conceptually possible that the relationship within every individual is actually negative if they were arranged like this figure:

This is also known as “Simpson’s paradox”
Technically Speaking…
This data set violates the assumption that the observations are independent and indentically distributed (i.i.d.). The data points are not all independent, because the pronunciations from within a speaker are going to be correlated. The data points are not all identically distributed because each speaker has their own characteristic distribution of data.
Thinking about Pooling
One way to start thinking about mixed effects models is to think about how you are “pooling” the data from your data sources. In this example, we’re talking about speakers, but this could also be study sites, lexical items, experimental subjects, stimulus items, etc.
Complete Pooling
What people have been doing for a long time is “complete pooling.” All of the data from all of the sources all just goes into one big data bucket. You then fit a model with all of this data in the bucket, undifferentiated by who contributed what data point.
For the reasons we’ve discussed already, this isn’t a great approach.
- It violates some statistical assumptions.
- The parameter estimates are over-confident.
- The parameter estimates are too skewed towards speakers/words with more data.
- It is possible for the structure of the data to give you exactly the wrong estimate.
No Pooling
One way you could try to resolve some of these problems would be to fit one model for every speaker. Here, you don’t pool the data at all. Each speaker just has their own bucket of data.
We’ll actually do this in a second, and then discuss the pros and cons.
Partial Pooling
The final option is to do “partial pooling”. You model with all of the data, but preserve information about which speaker contributed which data. This approach allows the “model” for each speaker to mutually inform each other.
This is a “mixed effects model”, which we’ll also look at.
Fitting no-pooling models
In this section, we’re going to fit some no-pooling models. It is not necessary to be able to do this to be able to fit mixed effects models, but I think this can help you understand what mixed effects models are doing.
While the no-pooling approach to modelling isn’t the most sophisticated (and you definitely can’t use their p-values), I think it is often a good idea to try it out as an exploratory technique. You can check out a talk by Hadley Wickham about it here.
It is pretty easy to fit one model for one speaker. We just take a subset of the data and fit the model:
speakers <- unique(ayT$idstring)
sp1 <- ayT %>%
filter(idstring == speakers[1])
sp1_mod <- lm(F1_n ~ dur_c, data = sp1)
summary(sp1_mod)
Call:
lm(formula = F1_n ~ dur_c, data = sp1)
Residuals:
Min 1Q Median 3Q Max
-1.06428 -0.32610 -0.01164 0.34649 1.15681
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.30902 0.05851 5.281 8.68e-07 ***
dur_c 0.39734 0.08841 4.494 2.05e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4442 on 91 degrees of freedom
Multiple R-squared: 0.1816, Adjusted R-squared: 0.1726
F-statistic: 20.2 on 1 and 91 DF, p-value: 2.05e-05
There is even a handy dandy function in the broom package called tidy() that will convert a linear model object (and many others) into a data frame.
tidy(sp1_mod)
But there are 326 speakers in this data set. We can’t go repeating this procedure that many times. I will be using tools from the tidyverse to fit one model for each speaker, and combine them all together. The exact details of how this works goes a bit beyond what we have time to cover here today, but if you are interested in how it works you can download the source code for this lecture from the Code tab at the top of the page.
The results of the no-pooling model is plotted below. For every speaker, I’ve plotted their estimated intercept along the x-axis and their estimated slope along the y-axis.

This no-pooling approach is informative, but also has some serious weaknesses. First of all, we can see that most speakers have the expected slope (on the y-axis) between duration and F1. That is, the slope is positive, meaning as duration increases, F1 increases (lowering the vowel). However, there is a lot if inter-speaker variability. Some speakers are estimated to have a fairly steep slope, and others have slopes closer to 0 or even negative.
Here’s a plot of the actual lines these parameters correspond to.

Discussion
What are the pros and cons of this no-pooling model?
Partial Pooling (Mixed Effects)
The biggest downside to the no pooling approach is that there is no shared information between the models. It’s possible that speakers who had a negative slope were only estimated to have a negative slope because they had very little data. If there were some way to incorporate information about the slopes of every other speaker into these speakers’ slope estimates, they might be considerably different.
This is exactly what Mixed Effects Models do. You define “grouping variables” or “pooling variables” or “random effects” in the model to tell the model to estimate effects for each speaker, but not to do so completely independently for each speaker.
~2 Minute Activity
Fit a complete pooling model with lm and a partial pooling model with lmer with the following code.
ayT_lm <-lm(F1_n ~ dur_c, data = ayT)
ayT_lme <- lmer(F1_n ~ dur_c + (1 + dur_c | idstring), data = ayT)
The big difference between the complete pooling and the partial pooling models are the definition of the “random effects” structures.
- Everything to the left of the
|
- Everything that can vary within the grouping variable.
1 refers to the intercept
- Everything to the right of the
|
With (1 + dur_c | idstring ), we’re saying
Speakers can have variable intercepts, and variable slopes.
Let’s look at the summary of the mixed effects model.
summary(ayT_lme)
Linear mixed model fit by REML ['lmerMod']
Formula: F1_n ~ dur_c + (1 + dur_c | idstring)
Data: ayT
REML criterion at convergence: 27306
Scaled residuals:
Min 1Q Median 3Q Max
-5.6543 -0.6010 -0.0430 0.5386 10.3140
Random effects:
Groups Name Variance Std.Dev. Corr
idstring (Intercept) 0.10060 0.3172
dur_c 0.01769 0.1330 -0.12
Residual 0.22564 0.4750
Number of obs: 19342, groups: idstring, 326
Fixed effects:
Estimate Std. Error t value
(Intercept) 0.58113 0.01827 31.81
dur_c 0.34284 0.01071 32.00
Correlation of Fixed Effects:
(Intr)
dur_c -0.092
The “Random Effects”
Strictly speaking, the mixed effects models aren’t estimating the actual speaker-level slopes and intercepts as proper parameters of the model. Instead, it’s estimating the covariance matrix of the slopes and the intercepts. In this summary it’s showing us
- The variance and standard deviation of individual level intercepts.
- The variance and standard deviation of individual level slopes.
- The correlation between the intercepts and slopes.
- The variance and standard deviation of the remaining residuals.
Here, it looks like speakers are more variable with respect to their baseline F1 than they are with respect to the effect duration has on their F1. And, the larger a speakers’ baseline F1 is, their effect of duration is somewhat weaker, but it’s not a very strong correlation.
Fixed Effects
These are the estimated “fixed effect”. They can be interpreted a lot like the coefficients of the models we’ve been fitting already, in the sense that these are part of the formula to draw a line. Another way is to interpret these as the average intercept and slope between speakers.
Looking at the random effects
It is possible to extract estimates of then random effects using the function ranef(). Strictly speaking, these are “BLUPs”, which is stands for “Best Linear Unbiased Predictors”. The point here is that these aren’t proper parameters of the model, but the distinction here is a bit arcane for an introductory course.
head(ranef(ayT_lme)$idstring)
These are the predicted differences in Intercept and slope for each speaker from the fixed effects. That is, if we added the (Intercept) value from the fixed effects to these random effects, we would get the predicted slope for each speaker. Let’s do that:
ayT_lme_fixef <- fixef(ayT_lme)
ranef(ayT_lme)$idstring %>%
ggplot(aes(`(Intercept)` + ayT_lme_fixef[1],
dur_c + ayT_lme_fixef[2]))+
geom_point()+
geom_hline(yintercept = 0, linetype = 2)+
geom_vline(xintercept = 0, linetype = 2)+
theme_minimal()+
coord_fixed()


We can get an idea of what the mixed-effects modelling has done by comparing these results to the no-pooling model. First, the clustering of individual speakers’ random effects is tighter. Also, no speaker is estimated to have an individual slope less than 0.
It is also possible to see the positive correlation between the random effects. Speakers who have a baseline lower ayT appear to be more affected by duration changes.
Multiple random effects
This is where it gets impossible to make illustrative graphs. It is also possible to include multiple grouping factors in a mixed effects model.
~5 minute break
We’re going to add word as a grouping factor. For now, we’ll treat word as only being able to modulate the baseline F1_n, which means we’ll add it with (1 | word) (a.k.a. a random intercept).
Go ahead and fit this model:
ayT_lme_multi <- lmer(F1_n ~ dur_c +
(1 + dur_c | idstring) +
(1 | word), data = ayT)
summary(ayT_lme_multi)
What happened?
However, it is possible to include a random slope by word too, so let’s do that as well:
ayT_lme_multi2 <- ayT_lme_multi <- lmer(F1_n ~ dur_c +
(1 + dur_c | idstring) +
(1 + dur_c| word), data = ayT)
summary(ayT_lme_multi2)
Linear mixed model fit by REML ['lmerMod']
Formula: F1_n ~ dur_c + (1 + dur_c | idstring) + (1 + dur_c | word)
Data: ayT
REML criterion at convergence: 26612
Scaled residuals:
Min 1Q Median 3Q Max
-6.1022 -0.5875 -0.0406 0.5347 10.2437
Random effects:
Groups Name Variance Std.Dev. Corr
idstring (Intercept) 0.100144 0.31645
dur_c 0.018412 0.13569 -0.17
word (Intercept) 0.059942 0.24483
dur_c 0.005643 0.07512 -0.01
Residual 0.214192 0.46281
Number of obs: 19342, groups: idstring, 326; word, 255
Fixed effects:
Estimate Std. Error t value
(Intercept) 0.66763 0.02868 23.28
dur_c 0.30469 0.01948 15.64
Correlation of Fixed Effects:
(Intr)
dur_c -0.176
One thing you might notice now is that the “fixed effect” of duration has gotten a bit smaller.
# complete pooling
coef(ayT_lm)
(Intercept) dur_c
0.4877373 0.4357102
# full ranef structure
fixef(ayT_lme_multi2)
(Intercept) dur_c
0.6676302 0.3046943
This may look scary, especially if the effect size gradually vanishes away, but this is exactly how mixed effects models are supposed to work. In some sense, in the complete-pooling model, we thought we were modelling the effect of duration, but actually some of that effect was actually due to the peculiarities of the words spoken, and who the speakers were.
When to add random intercepts/slopes?
Barr et al (2012) recommend (command?) fitting models with “maximal” random effects structures. That is, for every possible grouping factor, include a random slope for every grouping factor that’s logically possible. I think this is a good starting point, but isn’t always practical.
Logically Possible & Impossible Random Slopes
In the ayT model we just fit, it was possible for us to fit a random slope of duration by speaker and word, because speakers produced tokens with different duration, and words were produced with different durations.
However, if we wanted to include voicing again (pre-voiceless vs elsewhere), we could include a random slope of voicing by speaker, but not by word. This isn’t a prohibition, it’s just not logically possible and might blow up your model. That’s because each word only every has one voicing context. In the word, NICE, the following /s/ is voiceless, and always will be.
Similarly, if we wanted to include year of birth in the model, we could include a random slope of dob by word, because many words were spoken by people across many ages. But we couldn’t include a random slope of dob by speaker, because each speaker only has one date of birth.
Necessary Random Effects
Any time you are looking at a between-grouping factor variable, you should include the grouping factor with a random intercept. This is especially true for any kind of research done outside of an experimental lab context.
- age:
(1 | speaker)
- gender:
(1 | speaker)
- word frequency:
(1 | word)
- sentence grammaticality:
(1 | token)
Other necessary random effects would be related to the nature of the data. In this ah model, we haven’t explored any between-grouping factors, but all of these data points were produced by speakers, embedded in specific words, so it’s important to capture that in the random effects.
Recommended Random Effects
It is a good idea to include your biggest effects, or effects of greatest interest, as random slopes across the grouping factors which contain the most data.
The assumptions of LMEs
The way LMEs work is they make some strong assumptions abut the distribution of the random effects. Let’s look at the distribution of the parameters from the no-pooling model again (i.e. when we fit 1 model for each speaker).

These by-speaker parameters were estimated via maximum likelihood. That is, these are the estimated slopes and intercepts that best satisfy the linear regression formula.
The random intercepts and slopes are not estimated in this way. Rather, the model assumes that the random intercepts and slopes are drawn from a normal distribution. That is, the range of of possible random intercepts and slopes are constrained, so that they are consistent with being drawn from a normal distribution. This is what allows the estimates for each speaker to be “partially pooled.” Even if there is not very much data from a single speaker, we can still get some sense of what their individual slope ought to be if we we look at the mean and standard deviation of the slopes across all speakers.
This also leads to “shrinkage” of the estimated random effects. Compare the maximum likelihood estimates (in yellow) to the random effects (in grey) below. For the random slope especially, the range of values is much narrower.
Warning message:
In scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
EOF within quoted string

By and large, this shrinkage is a good thing. Let’s say that you ran a reaction time experiment, and then took your three subjects who pressed the button the fastest and the three subjects who pressed the button the slowest and re-tested them. Almost invariably, the three fastest subjects will be a bit slower on the second test, and the three slowest a bit faster. This is also known as “regression to the mean.” You could consider this shrinkage of the random effects to be “baking in” this phenomenon.
“Nuisance variables”
Another way to think about random effects is as “nuisance variables”. When modelling something as complex as why pronunciations change, there are always going to be factors missing from our models for a variety of reasons.
- there are things we know matter, but failed to measure them for some reason.
- there are things we know matter, but we don’t know how to measure them.
- there are things that may not be measureable.
- there are things we don’t realize matter.
If we don’t do our best to account for these “unmodellables”, they could very well mess with our fixed effects estimates. While they are not a perfect solution, random effects can go some way towards soaking up some of these unmodelable variables.
On the flip side, if you have something you know has an effect, include it in the model. For example, we know that gender has a big effect on many changes in progress. You should, therefore, include it in the model instead of hoping that the random effects will account for it. That’s because if there is a big between-subject variable that affects the outcome variable, the assumption that speaker random intercepts & slopes are drawn from a single normal distribution is violated.
LS0tCnRpdGxlOiAiSW50cm9kdWNpbmcgTWl4ZWQgRWZmZWN0cyBNb2RlbHMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIGNzczogLi4vY3VzdG9tLmNzcwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDMKLS0tCgojIEFnZW5kYQoKMS4gQSAqYnJpZWYqIHJldmlldyBvZiBub24tR2F1c3NpYW4gbW9kZWxzLgoyLiBUaGUgTW90aXZhdGlvbnMgZm9yIE1peGVkIEVmZmVjdHMgTW9kZWxzCjMuIEhvdyB0byBmaXQgTWl4ZWQgRWZmZWN0cyBNb2RlbHMuCgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobG1lNCkKbGlicmFyeShtdWx0aXZhcmlhdGUyMDE3KQoKYGBgCgojIEJyaWVmIHJldmlldyBvZiBub24tZ2F1c3NpYW4gbW9kZWxzCgpXZSdyZSBnb2luZyB0byAqYnJpZWZseSogY292ZXIgbm9uLUdhdXNzaWFuIG1vZGVscywgaW4gb3JkZXIgdG8gYXZvaWQgdGhlIHN5bXB0b20gb2YgIndoZW4geW91IGhhdmUgYSBoYW1tZXIsIGV2ZXJ5dGhpbmcgbG9va3MgbGlrZSBhIG5haWwuIgoKV2hlbiBub3Qgd29ya2luZyB3aXRoIGNvbnRpbnVvdXMgZGF0YSwgdGhlIG1vc3QgY29tbW9uIGtpbmQgb2YgZGF0YSB5b3UncmUgbGlrZWx5IHRvIHdvcmsgd2l0aCBpcyAqY291bnQqIGRhdGEgb2Ygc29tZSBraW5kLiBUaGlzIGNvdW50IGRhdGEgY2FuIGhhdmUgdHdvIGRpZmZlcmVudCBxdWFsaXRpZXMuCgotICoqUmF0ZSoqIC0gSG93IG9mdGVuIGRpZCBzb21ldGhpbmcgaGFwcGVuIGF0IGFsbCwgb3IgcGVyIHNvbWUgdW5pdCBvZiB0aW1lLgotICoqUHJvcG9ydGlvbioqIC0gSG93IG9mdGVuIGRpZCBzb21ldGhpbmcgaGFwcGVuIG91dCBvZiBhbGwgcG9zc2libGUgaW5zdGFuY2VzIGl0IGNvdWxkIGhhdmUgaGFwcGVuZWQuCgpUaGVzZSB0d28ga2luZHMgb2YgZGF0YSBjYWxsIGZvciBkaWZmZXJlbnQgKmdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMqLgoKLSAqKlJhdGUqKiAgLSB1c2UgYSBQb2lzc29uIG1vZGVsLgotICoqUHJvcG9ydGlvbioqIC0gdXNlIGEgTG9naXN0aWMgbW9kZWwuCgpXZSdsbCB3YWxrIHRocm91Z2ggdGhlc2UgYnJpZWZseSB1c2luZyB0aGUgZXhhbXBsZSBvZiAqZmlsbGVkIHBhdXNlcyouCgo8ZGl2IGNsYXNzID0gImJveCBicmVhayI+CjxzcGFuIGNsYXNzID0gImJpZy1sYWJlbCI+RmlsbGVkIFBhdXNlczxzcGFuPgoKU29tZXRpbWVzIHdoZW4gc3BlYWtpbmcsIHNwZWFrZXJzIGV4cGVyaWVuY2Ugc28tY2FsbGVkICJkaXNmbHVlbmNpZXMuIgpBbW9uZyBkaXNmbHVlbmNpZXMsIGZpbGxlZCBwYXVzZXMgaGF2ZSBiZWVuIHRyZWF0ZWQgYXMgYmVpbmcgYSBzcGVjaWFsIHNvcnQuIApJbiBBbWVyaWNhbiBFbmdsaXNoIFdyaXRpbmcgdGhlc2UgYXJlIHVzdWFsbHkgd3JpdHRlbiBvdXQgYXMgPCp1bSo+IGFuZCA8KnVoKj4sCmFuZCBpbiBCcml0aXNoIEVuZ2xpc2ggV3JpdGluZyB0aGV5J3JlIHVzdWFsbHkgd3JpdHRlbiBvdXQgYXMgPCplcm0qPiBhbmQgPCplcio+LgpXaGlsZSB0aGUgZXhhY3QgcXVhbGl0eSBvZiB0aGUgdm93ZWwgY2FuIGRpZmZlciBiZXR3ZWVuIHZhcmlldGllcyBhbmQgZGlhbGVjdHMsIHdlJ3JlIGdvaW5nIHRvIGZvY3VzIG9uIGp1c3QgdGhlIGFsdGVybmF0aW9uIGJldHdlZW4gd2hldGhlciBpdCBlbmRzIGluIGFuIC9tLyBvciB1cyBqdXN0IGFuIHVuc3RyZXNzZWQgdm93ZWwuCgo8L2Rpdj4KClRoZSBkYXRhIGhlcmUgaXMgZHJhd24gZnJvbSBuYXR1cmFsaXN0aWMgc29jaW9saW5ndWlzdGljIGludGVydmlld3MgY2FycmllZCBvdXQgaW4gUGhpbGFkZWxwaGlhLgpZb3UgY2FuIGFjY2VzcyB0aGUgZGF0YSB5b3Vyc2VsZiBpZiB5b3UgcnVuCgpgYGB7cn0KbGlicmFyeShkZXZ0b29scykKaW5zdGFsbF9naXRodWIoImpvZnJod2xkL1VoVW0iKQpgYGAKCgpgYGB7cn0KbGlicmFyeShVaFVtKQpgYGAKCiMjIFBvaXNzb24gcmVncmVzc2lvbgoKRm9yIGV2ZXJ5IHNwZWFrZXIsIHdlJ2xsIGZpcnN0IG1vZGVsIGhvdyBvZnRlbiB0aGV5IHVzZWQgZmlsbGVkIHBhdXNlcyBhdCBhbGwuClRoaXMgd2lsbCBpbnZvbHZlIGNvdW50aW5nIHVwIGFsbCBvZiB0aGVpciBmaWxsZWQgcGF1c2VzLCBhcyB3ZWxsIGFzIGhvdyBtYW55IHRvdGFsIHdvcmRzIHRoZXkgc3Bva2UuCkl0J3MgbmVjZXNzYXJ5IHRvIGNvdW50IHVwIGhvdyBtYW55IHRvdGFsIHdvcmRzIHdlcmUgc3Bva2VuLCBiZWNhdXNlIG5vdCBhbGwgaW50ZXJ2aWV3cyB3ZXJlIHRoZSBzYW1lIGxlbmd0aCwgbWVhbmluZyBzcGVha2VycyBoYWQgZGlmZmVyZW50aWFsIG9wcG9ydHVuaXR5IHRvIHVzZSBmaWxsZWQgcGF1c2VzLgpUaGUgZHVyYXRpb24gb2YgdGhlIGludGVydmlldyBpcyB0aGUgKmV4cG9zdXJlIHZhcmlhYmxlLioKCmBgYHtyfQpmcF9jb3VudCA8LSB1bV9QTkMgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKGFnZTAgPSAoYWdlLTIwKS8xMCklPiUKICAgICAgICAgICAgICBncm91cF9ieShpZHN0cmluZywgCiAgICAgICAgICAgICAgICAgICAgICAgYWdlMCwgCiAgICAgICAgICAgICAgICAgICAgICAgc2V4LCAKICAgICAgICAgICAgICAgICAgICAgICBud29yZHMpICU+JQogICAgICAgICAgICAgIGNvdW50KCkKYGBgCgoKCgpXZSdsbCBsb29rIGF0IHRoZSBlZmZlY3Qgb2YgYWdlIGFuZCBzZXggb24gdGhlIG92ZXJhbGwgcmF0ZSBvZiBmaWxsZWQgcGF1c2VzIGxpa2Ugc286CgpgYGB7cn0KZ2dwbG90KGZwX2NvdW50LCBhZXMoYWdlMCwgKG4vbndvcmRzKSoxMDAsIGNvbG9yID0gc2V4KSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogICAgdGhlbWVfYncoKQpgYGAKCgpgYGB7cn0KZnBfbW9kZWwgPC0gZ2xtKG4gfiBhZ2UwICogc2V4LCAKICAgICAgICAgICAgICAgIG9mZnNldCA9IGxvZyhud29yZHMpLCAKICAgICAgICAgICAgICAgIGRhdGEgPSBmcF9jb3VudCwKICAgICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24pCmBgYAoKYGBge3J9CnN1bW1hcnkoZnBfbW9kZWwpCmBgYAoKV2l0aG91dCBleGFjdGx5IHVuZGVyc3RhbmRpbmcgd2hhdCB0aGUgZXhhY3QgbnVtYmVycyBtZWFuLCB3ZSBjYW4gd2FsayBhd2F5IHdpdGggdGhpcyB1bmRlcnN0YW5kaW5nOgoKLSB0aGUgbGFyZ2UgbmVnYXRpdmUgaW50ZXJjZXB0IG1lYW5zIHRoYXQgZmlsbGVkIHBhdXNlcyBhcmUgcmVsYXRpdmVseSByYXJlIChidXQgd2Ugc2hvdWxkIGNvbXBhcmUgdGhpcyB0byBvdGhlciB3b3JkcyB0byBiZSBzdXJlKS8KLSBUaGUgcG9zaXRpdmUgYWdlIGVmZmVjdCBtZWFucyB0aGF0IGFzIHBlb3BsZSBnZXQgb2xkZXIsIHRoZWlyIHJhdGUgb2YgZmlsbGVkIHBhdXNlcyBpbmNyZWFzZXMuCi0gVGhlIHBvc2l0aXZlIHNleCBlZmZlY3QgbWVhbnMgdGhhdCBtZW4gdXNlIGZpbGxlZCBwYXVzZXMgYSBiaXQgbW9yZSBvZnRlbiB0aGFuIHdvbWVuLgotIFRoZSBwb3NpdGl2ZSBpbnRlcmFjdGlvbiBlZmZlY3QgbWVhbnMgdGhhdCB0aGUgYWdlIGVmZmVjdCBpcyBhIHF1aXRlIGEgYml0IHN0cm9uZ2VyIGZvciBtZW4uCgpUaGUgc3BlY2lmaWMgZXN0aW1hdGVzIGZvciB0aGUgbW9kZWwgYXJlOgoKYGBge3J9CiMgRmlsbGVkIHBhdXNlcyBwZXIgMTAwMCB3b3JkcyBhdCBhZ2UwPT0wLCBzZXg9PWYKZXhwKC00LjI1MDQzNCkgKiAxMDAwCgojIEZpbGxlZCBwYXVzZXMgcGVyIDEwMDAgd29yZHMgYWdlMD09Miwgc2V4PT1mCmV4cCgtNC4yNTA0MzQgKyAoMiowLjA1MDUwMikpICogMTAwMAoKIyBGaWxsZWQgcGF1c2VzIHBlciAxMDAwIHdvcmRzIGF0IGFnZTA9PTAsIHNleD09bQpleHAoLTQuMjUwNDM0ICsgMC4xNjYwNjQpICogMTAwMAoKIyBGaWxsZWQgcGF1c2VzIHBlciAxMDAwIHdvcmRzIGF0IGFnZTA9PTIsIHNleD09bQpleHAoLTQuMjUwNDM0ICsgMC4xNjYwNjQgKyAoMiAqICgwLjA1MDUwMiArIDAuMDMwNDI3ICkpKSAqIDEwMDAKYGBgCgoKIyMgTG9naXN0aWMgcmVncmVzc2lvbgoKSWYgd2UncmUgaW50ZXJlc3RlZCBub3QganVzdCBpbiB0aGVpciBvdmVyYWxsIHJhdGUgb2YgZmlsbGVkIHBhdXNlIHVzZSwgYnV0IHJhdGhlciB3aGVuIHRoZXkgdXNlZCBhIGZpbGxlZCBwYXVzZSwgd2hpY2ggb25lIGRpZCB0aGV5IHVzZSwgd2Ugd291bGQgZml0IGEgbG9naXN0aWMgcmVncmVzc2lvbi4KCmBgYHtyfQp1bV9kZiA8LSB1bV9QTkMgJT4lCiAgICAgICAgICAgIG11dGF0ZShpc191bSA9ICh3b3JkID09ICJVTSIpICogMSwKICAgICAgICAgICAgICAgICAgIGFnZTAgPSAoYWdlLTIwKS8xMCkKCnVtX3Byb3BvcnRpb24gPC0gdW1fZGYgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGlkc3RyaW5nLCBhZ2UwLCBzZXgpJT4lCiAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSh1bV9wcm9wID0gbWVhbihpc191bSkpCmBgYAoKYGBge3J9CmdncGxvdCh1bV9wcm9wb3J0aW9uLCBhZXMoYWdlMCwgdW1fcHJvcCwgY29sb3IgPSBzZXgpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikrCiAgICB0aGVtZV9idygpCmBgYAoKYGBge3J9CnVtX21vZGVsIDwtIGdsbShpc191bX5hZ2UwKnNleCwgCiAgICAgICAgICAgICAgICBkYXRhID0gdW1fZGYsCiAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCkKYGBgCgoKYGBge3J9CnN1bW1hcnkodW1fbW9kZWwpCmBgYAoKCgoKIyBUaGUgcmF0aW9uYWxlIGJlaGluZCBMTUVzCgpUaGUgb3JpZ2luYWwgcmVhc29uaW5nIGJlaGluZCBtb3ZpbmcgdG8gbGluZWFyIG1peGVkIGVmZmVjdHMgbW9kZWxsaW5nIGhhcyBhIGxvdCB0byBkbyB3aXRoIHNvcGhpc3RpY2F0ZWQgc3RhdGlzdGljYWwgcmVhc29uaW5nIHdoaWNoIEknbGwganVzdCBicmllZmx5IGRpc2N1c3MuIExldCdzIHJldHVybiB0byBvdXIgYGF5VGAgZGF0YS4KUmVjYWxsLCB0aGlzIGlzIGEgY29sbGVjdGlvbiBvZiAvYXkvIHByb251bmNpYXRpb25zIGdhdGhlcmVkIGZyb20gcmVjb3JkZWQgaW50ZXJ2aWV3cyB3aXRoICBgciBsZW5ndGgodW5pcXVlKGF5JGlkc3RyaW5nKSlgIHNwZWFrZXJzIGZyb20gUGhpbGFkZWxwaGlhLgpUb2RheSwgd2UnbGwgYmUgbG9va2luZyBhdCB0aGUgZWZmZWN0IG9mIHRoZSB2b3dlbHMnICpkdXJhdGlvbiogb24gdGhlIG5vcm1hbGl6ZWQgRjEuCgpUbyBzdGFydCBvZmYsIHdlJ2xsIGJlIHRyYW5zZm9ybWluZyB0aGUgZHVyYXRpb24gcHJlZGljdG9yLiAKU3BlY2lmaWNhbGx5LCBJJ2xsIGJlIGxvZzIgdHJhbnNmb3JtaW5nIGl0LCB0aGVuIHN1YnRyYWN0aW5nIHRoZSBtZWRpYW4uCkluIG1hdGhlbWF0aWNhbCBub3RhdGlvbiB0aGF0J3MgCgokJApcdGV4dHtkdXJfY30gPSBcbG9nXzIoXHRleHR7ZHVyYXRpb259KS1tZWRpYW4oXGxvZ18yKFx0ZXh0e2R1cmF0aW9ufSkpCiQkCgpUaGUgcmVhc29uIEknbSBkb2luZyB0aGlzIHRyYW5zZm9ybWF0aW9uIGlzIGJlY2F1c2UgZHVyYXRpb24gdmFsdWVzIHRlbmQgdG8gaGF2ZSBhIGxvbmcsIHJpZ2h0d2FyZCB0YWlsLgpMb2cgdHJhbnNmb3JtaW5nIHRoZSBkdXJhdGlvbiBoZWxwcyBtYWtlIHRoZSBkaXN0cmlidXRpb24gYSBiaXQgbW9yZSBzeW1tZXRyaWNhbC4KCjxkaXYgc3R5bGUgPSAid2lkdGg6MTAwJTtmbG9hdDpsZWZ0OyI+CjxkaXYgc3R5bGUgPSAid2lkdGg6NDUlO2Zsb2F0OmxlZnQ7bWFyZ2luOmF1dG87Ij4KYGBge3IgZWNobyA9IEYsIGZpZy53aWR0aCA9IDEsIGZpZy5oZWlnaHQgPSAxfQoKYXlUIDwtIGF5ICU+JSBmaWx0ZXIocGx0X3ZjbGFzcz09ImF5MCIpCmdncGxvdChheVQsIGFlcyhkdXIpKSsKICAgIHN0YXRfZGVuc2l0eShjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC44KSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKPC9kaXY+CjxkaXYgc3R5bGUgPSAid2lkdGg6NDUlO2Zsb2F0OmxlZnQ7bWFyZ2luOmF1dG87Ij4KYGBge3IgZWNobyA9IEYsIGZpZy53aWR0aCA9IDEsIGZpZy5oZWlnaHQgPSAxfQpnZ3Bsb3QoYXlULCBhZXMobG9nMihkdXIpKSkrCiAgICBzdGF0X2RlbnNpdHkoY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuOCkrCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCjwvZGl2Pgo8L2Rpdj4KCkEgbG9nIHRyYW5zZm9ybSBvZiBhbnkgYmFzZSB3b3VsZCBkbyB0aGUgam9iLCBhY3R1YWxseSAoZS5nLiBuYXR1cmFsIGxvZywgb3IgYGxvZygpYCBvciBgbG9nMTAoKWApLiAKSSBjaG9zZSBsb2cyIGJlY2F1c2Ugb2YgdGhlIGVmZmVjdCBpdCBoYXMgb24gaW50ZXJwcmV0aW5nIHRoZSBzbG9wZS4KRXZlcnkgaW5jcmVhc2Ugb2YgMSBvbiB0aGUgbG9nMiBzY2FsZSBjb3JyZXNwb25kcyB0byAqZG91YmxpbmcqIHRoZSBkdXJhdGlvbi4KU28sIGluc3RlYWQgb2Ygc2F5aW5nICJ0aGUgZWZmZWN0IG9mIGxvZyhkdXJhdGlvbikgaXMgWCIsIHdlIGNhbiBzYXkgICJ0aGUgZWZmZWN0IG9mIGRvdWJsaW5nIGR1cmF0aW9uIGlzIFgiLgoKSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IEknbSBhbHNvIG9ubHkgZG9pbmcgdGhpcyBiZWNhdXNlIEkgZG9uJ3QgaGF2ZSBhIHNwZWNpZmljIHRoZW9yeSBhYm91dCB3aHkgdGhlIGVmZmVjdCBvZiBkdXJhdGlvbiBzaG91bGQgYmUgYWRkaXRpdmUuClNvbWUgaW5mb3JtYXRpb24gcHJvY2Vzc2luZyB0aGVvcmllcyBoYXZlIHNwZWNpZmljIHByZWRpY3Rpb25zIGFib3V0ICphZGRpdGl2ZSogZWZmZWN0cyBvZiByZWFjdGlvbiB0aW1lcywgYW5kIGluIHRob3NlIGNhc2VzIHlvdSBtYXliZSBzaG91bGRuJ3QgbG9nIFJUcyAoW0xvICYgQW5kcmV3cyAyMDE1XShodHRwczovL2R4LmRvaS5vcmcvMTAuMzM4OSUyRmZwc3lnLjIwMTUuMDExNzEpKS4KCgpgYGB7cn0KIyBmaWx0ZXIoKSBnZXRzIGp1c3QgdGhlIHN1YnNldCBvZiB0aGUgZGF0YSB0aGF0IGlzIHByZS12b2ljZWxlc3MKIyBJIGxvZzIgYW5kIGNlbnRlciB0aGUgZHVyYXRpb24gaW4gdHdvIHN0ZXBzIGluc2lkZSBtdXRhdGUoKS4KYXlUIDwtIGF5ICU+JSAKICAgICAgICAgIGZpbHRlcihwbHRfdmNsYXNzID09ICJheTAiKSAlPiUKICAgICAgICAgIG11dGF0ZShsb2cyX2R1ciA9IGxvZzIoZHVyKSwKICAgICAgICAgICAgICAgICBkdXJfYyA9IGxvZzJfZHVyIC0gbWVkaWFuKGxvZzJfZHVyKSwKICAgICAgICAgICAgICAgICBkb2IgPSB5ZWFyLWFnZSwKICAgICAgICAgICAgICAgICBkZWNhZGUgPSAoZG9iLTE5MDApLzEwKQpgYGAKCgoKYGBge3J9CmF5VCAlPiUgCiAgZ2dwbG90KGFlcyhkdXJfYywgRjFfbikpKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDUpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAncmVkJykrCiAgICB0aGVtZV9idygpCmBgYAoKWW91IG1heSBub3QgZXZlbiBiZSBhYmxlIHRvIHRlbGwgdGhhdCB0aGUgcmVncmVzc2lvbiBsaW5lIGhhcyBoYXMgYSBjb25maWRlbmNlIGludGVydmFsIGJlY2F1c2UgaXQgaXMgbmFycm93ZXIgdGhhbiB0aGUgd2lkdGggb2YgdGhlIGxpbmUhIFRoYXQncyBiZWNhdXNlIHRoZSBtb2RlbCBoYXMgbG93IHVuY2VydGFpbnR5IGFib3V0IHRoZSBzbG9wZToKCmBgYHtyfQpzdW1tYXJ5KGxtKEYxX24gfiBkdXJfYywgZGF0YSA9IGF5VCkpCmBgYApCdXQgaW4gYW4gaW1wb3J0YW50IHNlbnNlLCB0aGlzIG1vZGVsIGlzICpvdmVybHkqIGNvbmZpZGVudC4gSXQgdGhpbmtzIGl0J3Mgd29ya2luZyB3aXRoIGByIGZvcm1hdEMobnJvdyhheVQpLCBiaWcubWFyayA9ICIsIilgICppbmRlcGVuZGVudCogb2JzZXJ2YXRpb25zLiBBcyBpZiBgciBmb3JtYXRDKG5yb3coYXlUKSwgYmlnLm1hcmsgPSAiLCIpYCBkaWZmZXJlbnQgcGVvcGxlIHdhbGtlZCB1cCB0byBhIG1pY3JvcGhvbmUgYW5kIHNhaWQgYGF5YC4gQnV0IHRoYXQgaXMgZXhhY3RseSBub3Qgd2hhdCBoYXBwZW5lZCBoZXJlLiBJbnN0ZWFkLCBhIHNtYWxsZXIgbnVtYmVyIG9mIHNwZWFrZXJzIChgciBsZW5ndGgodW5pcXVlKGF5VCRpZHN0cmluZykpYCkgaGFkIG1hbnkgdG9rZW5zIG9mIGBheWAsIGFuZCBub3QgYWx3YXlzIHRoZSBzYW1lIG51bWJlciBvZiB0b2tlbnMgZWFjaC4KClRvIG1ha2UgdGhlIGV4YW1wbGUgbW9yZSBleHRyZW1lLCBsZXQncyBpbWFnaW5lIHdlIGhhZCBkYXRhIGZyb20gb25seSB0d28gc3BlYWtlcnMsIG9uZSB3aG8gcHJvZHVjZWQgdmVyeSBtYW55IHRva2VucywgYW5kIHdobyB3aG8gcHJvZHVjZWQgcmVsYXRpdmVseSBmZXcuCgoKYGBge3IgZWNobyA9IEZ9CmF5VCAlPiUKICBtdXRhdGUoaWRzdHJpbmcgPSBhcy5jaGFyYWN0ZXIoaWRzdHJpbmcpKSU+JQogIGZpbHRlcihpZHN0cmluZyAlaW4lIGMoICJQSDg0LTItNi0iLCAiUEg4NS0yLTItIikpJT4lCiAgZ2dwbG90KGFlcyhkdXJfYywgRjFfbikpKwogICAgZ2VvbV9wb2ludCgpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJykrCiAgICBmYWNldF93cmFwKH5pZHN0cmluZykrCiAgICB0aGVtZV9idygpCmBgYAoKQmFzZWQgb24gKmp1c3QqIHRoZXNlIHR3byBzcGVha2VycywgaXQgd291bGQgYmUgaGFyZCB0byBzYXkgd2hhdCAgdGhlIHJlYWwgZWZmZWN0IG9mIGR1cmF0aW9uIG9uIEYxIGlzLgpPbmUgc3BlYWtlciBoYXMgYSBmYWlybHkgcG9zaXRpdmUgc2xvcGUsIGFuZCB0aGUgb3RoZXIgaGFzIGEgZmFpcmx5IG5lZ2F0aXZlIHNsb3BlLgpIb3dldmVyLCBpZiB5b3UgZml0IGEgbW9kZWwgd2l0aCBqdXN0IHRoZXNlIHR3byBzcGVha2VycycgZGF0YSBpbiB0aGUgbW9kZWwsIHRoZSBlc3RpbWF0ZWQgc2xvcGUgd291bGQgYmUgYmUgZG9taW5hdGVkIGJ5IHRoZSBzcGVha2VyIHdpdGggYSBsb3Qgb2YgZGF0YSwgYW5kIGFsbW9zdCBub25lIGdpdmVuIHRvIHRoZSBzcGVha2VyIHdpdGggdmVyeSBsaXR0bGUuIAoKYGBge3IgZWNobyA9IEZ9CmF5VCAlPiUKICBtdXRhdGUoaWRzdHJpbmcgPSBhcy5jaGFyYWN0ZXIoaWRzdHJpbmcpKSU+JQogIGZpbHRlcihpZHN0cmluZyAlaW4lIGMoICJQSDg0LTItNi0iLCAiUEg4NS0yLTItIikpJT4lCiAgbG0oRjFfbiB+IGR1cl9jICwgZGF0YSA9IC4pJT4lCiAgc3VtbWFyeSgpCmBgYAoKSG93ZXZlciwgdGhpcyBpcyBub3QgaWRlYWwsIHNpbmNlIHdlIHNob3VsZCBnaXZlIGEgYml0IG1vcmUgd2VpZ2h0IHRvIHRoZSBmYWN0IHRoYXQgYXQgbGVhc3Qgb25lIHNwZWFrZXIgaGFzIGEgd2Vha2VyIGVmZmVjdCwgZXZlbiBpZiB0aGV5IGhhdmUgbGVzcyBkYXRhLgpBbiBldmVuIG1vcmUgcGVydmVyc2Ugc2l0dWF0aW9uIGNvdWxkIGFyaXNlIGlmIHRoZXJlJ3MgYSBzdHJvbmcgY29ycmVsYXRpb24gYmV0d2VlbiBhIHRoZSBzcGVha2VyIGFuZCB0aGVpciBpbnRlcmNlcHQuIEZvciBleGFtcGxlLCBpbiB0aGVzZSBmaWd1cmVzIGl0IGxvb2tzIGxpa2UgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGR1cmF0aW9uIGFuZCBGMSBpcyAqcG9zaXRpdmUqLCBidXQgaXQncyBjb25jZXB0dWFsbHkgcG9zc2libGUgdGhhdCB0aGUgcmVsYXRpb25zaGlwIHdpdGhpbiBldmVyeSBpbmRpdmlkdWFsIGlzIGFjdHVhbGx5ICpuZWdhdGl2ZSogaWYgdGhleSB3ZXJlIGFycmFuZ2VkIGxpa2UgdGhpcyBmaWd1cmU6CgoKYGBge3IgZWNobyA9IEZ9CnBvaW50X2xpbmVfZGlzdGFuY2UgPC0gZnVuY3Rpb24oYiwgbSwgeCwgeSkKICAoeSAtIChtKnggKyBiKSkvc3FydChtXjIgKyAxKQoKY29uZm91bmRlZF9kYXRhX2ZyYW1lIDwtIGZ1bmN0aW9uKHgsIHksIG0sIG51bV9ncnApewogIGIgPC0gMCAjIGludGVyY2VwdCBkb2Vzbid0IG1hdHRlcgogIGQgPC0gcG9pbnRfbGluZV9kaXN0YW5jZShiLCBtLCB4LCB5KQogIGRfc2NhbGVkIDwtIDAuMDAwNSArIDAuOTk5ICogKGQgLSBtaW4oZCkpLyhtYXgoZCkgLSBtaW4oZCkpICMgYXZvaWQgMCBhbmQgMQogIGRhdGEuZnJhbWUoeD14LCB5PXksIAogICAgICAgICAgICBncm91cD1hcy5mYWN0b3Ioc3ByaW50ZigiZ3JwJTAyZCIsIGNlaWxpbmcobnVtX2dycCooZF9zY2FsZWQpKSkpKQp9Cgpjb25mb3VuZGVkX2R1ciA8LSBjb25mb3VuZGVkX2RhdGFfZnJhbWUoeCA9IGF5VCRkdXJfYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBheVQkRjFfbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSAtMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX2dycCA9IDEwKQoKY29uZm91bmRlZF9kdXIgJT4lCiAgZmlsdGVyKGdyb3VwICE9ICJncnAxMCIpJT4lCiAgZ2dwbG90KGFlcyh4LCB5LCBjb2xvciA9IGdyb3VwKSkrCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSAnbG0nLCBzZSA9IEYpKwogICAgeGxhYigiZHVyX2MiKSsKICAgIHlsYWIoIkYxX24iKSsKICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKGd1aWRlID0gIm5vbmUiKSsKICAgIHRoZW1lX21pbmltYWwoKQoKYGBgCgpUaGlzIGlzIGFsc28ga25vd24gYXMgIlNpbXBzb24ncyBwYXJhZG94IgoKIyMgVGVjaG5pY2FsbHkgU3BlYWtpbmcuLi4KClRoaXMgZGF0YSBzZXQgdmlvbGF0ZXMgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgb2JzZXJ2YXRpb25zIGFyZSAqaW5kZXBlbmRlbnQgYW5kIGluZGVudGljYWxseSBkaXN0cmlidXRlZCogKGkuaS5kLikuIApUaGUgZGF0YSBwb2ludHMgYXJlIG5vdCBhbGwgKmluZGVwZW5kZW50KiwgYmVjYXVzZSB0aGUgcHJvbnVuY2lhdGlvbnMgZnJvbSB3aXRoaW4gYSBzcGVha2VyIGFyZSBnb2luZyB0byBiZSBjb3JyZWxhdGVkLgpUaGUgZGF0YSBwb2ludHMgYXJlIG5vdCBhbGwgKmlkZW50aWNhbGx5IGRpc3RyaWJ1dGVkKiBiZWNhdXNlIGVhY2ggc3BlYWtlciBoYXMgdGhlaXIgb3duIGNoYXJhY3RlcmlzdGljIGRpc3RyaWJ1dGlvbiBvZiBkYXRhLgoKCiMgVGhpbmtpbmcgYWJvdXQgUG9vbGluZwoKT25lIHdheSB0byBzdGFydCB0aGlua2luZyBhYm91dCBtaXhlZCBlZmZlY3RzIG1vZGVscyBpcyB0byB0aGluayBhYm91dCBob3cgeW91IGFyZSAicG9vbGluZyIgdGhlIGRhdGEgZnJvbSB5b3VyIGRhdGEgc291cmNlcy4gSW4gdGhpcyBleGFtcGxlLCB3ZSdyZSB0YWxraW5nIGFib3V0IHNwZWFrZXJzLCBidXQgdGhpcyBjb3VsZCBhbHNvIGJlIHN0dWR5IHNpdGVzLCBsZXhpY2FsIGl0ZW1zLCBleHBlcmltZW50YWwgc3ViamVjdHMsIHN0aW11bHVzIGl0ZW1zLCBldGMuCgoKIyMgQ29tcGxldGUgUG9vbGluZwpXaGF0IHBlb3BsZSBoYXZlIGJlZW4gZG9pbmcgZm9yIGEgbG9uZyB0aW1lIGlzICJjb21wbGV0ZSBwb29saW5nLiIgQWxsIG9mIHRoZSBkYXRhIGZyb20gYWxsIG9mIHRoZSBzb3VyY2VzIGFsbCBqdXN0IGdvZXMgaW50byBvbmUgYmlnIGRhdGEgYnVja2V0LiBZb3UgdGhlbiBmaXQgYSBtb2RlbCB3aXRoIGFsbCBvZiB0aGlzIGRhdGEgaW4gdGhlIGJ1Y2tldCwgdW5kaWZmZXJlbnRpYXRlZCBieSB3aG8gY29udHJpYnV0ZWQgd2hhdCBkYXRhIHBvaW50LgoKIVtdKGZpZ3VyZXMvY29tcGxldGVfcG9vbGluZy5zdmcpCgpGb3IgdGhlIHJlYXNvbnMgd2UndmUgZGlzY3Vzc2VkIGFscmVhZHksIHRoaXMgaXNuJ3QgYSBncmVhdCBhcHByb2FjaC4KCjEuIEl0IHZpb2xhdGVzIHNvbWUgc3RhdGlzdGljYWwgYXNzdW1wdGlvbnMuCjIuIFRoZSBwYXJhbWV0ZXIgZXN0aW1hdGVzIGFyZSBvdmVyLWNvbmZpZGVudC4KMy4gVGhlIHBhcmFtZXRlciBlc3RpbWF0ZXMgYXJlIHRvbyBza2V3ZWQgdG93YXJkcyBzcGVha2Vycy93b3JkcyB3aXRoIG1vcmUgZGF0YS4KNC4gSXQgaXMgcG9zc2libGUgZm9yIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgdG8gZ2l2ZSB5b3UgZXhhY3RseSB0aGUgd3JvbmcgZXN0aW1hdGUuCgoKIyMgTm8gUG9vbGluZwoKT25lIHdheSB5b3UgY291bGQgdHJ5IHRvIHJlc29sdmUgc29tZSBvZiB0aGVzZSBwcm9ibGVtcyB3b3VsZCBiZSB0byBmaXQgb25lIG1vZGVsIGZvciBldmVyeSBzcGVha2VyLiBIZXJlLCB5b3UgZG9uJ3QgcG9vbCB0aGUgZGF0YSBhdCBhbGwuIEVhY2ggc3BlYWtlciBqdXN0IGhhcyB0aGVpciBvd24gYnVja2V0IG9mIGRhdGEuCgohW10oZmlndXJlcy9ub19wb29saW5nLnN2ZykKCldlJ2xsIGFjdHVhbGx5IGRvIHRoaXMgaW4gYSBzZWNvbmQsIGFuZCB0aGVuIGRpc2N1c3MgdGhlIHByb3MgYW5kIGNvbnMuCgoKIyMgUGFydGlhbCBQb29saW5nCgpUaGUgZmluYWwgb3B0aW9uIGlzIHRvIGRvICJwYXJ0aWFsIHBvb2xpbmciLiBZb3UgbW9kZWwgd2l0aCBhbGwgb2YgdGhlIGRhdGEsIGJ1dCBwcmVzZXJ2ZSBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCBzcGVha2VyIGNvbnRyaWJ1dGVkIHdoaWNoIGRhdGEuIFRoaXMgYXBwcm9hY2ggYWxsb3dzIHRoZSAibW9kZWwiIGZvciBlYWNoIHNwZWFrZXIgdG8gbXV0dWFsbHkgaW5mb3JtIGVhY2ggb3RoZXIuIAoKCiFbXShmaWd1cmVzL3BhcnRpYWxfcG9vbGluZy5zdmcpCgpUaGlzIGlzIGEgIm1peGVkIGVmZmVjdHMgbW9kZWwiLCB3aGljaCB3ZSdsbCBhbHNvIGxvb2sgYXQuCgojIEZpdHRpbmcgbm8tcG9vbGluZyBtb2RlbHMKCkluIHRoaXMgc2VjdGlvbiwgd2UncmUgZ29pbmcgdG8gZml0IHNvbWUgbm8tcG9vbGluZyBtb2RlbHMuIEl0IGlzIG5vdCBuZWNlc3NhcnkgdG8gYmUgYWJsZSB0byBkbyB0aGlzIHRvIGJlIGFibGUgdG8gZml0IG1peGVkIGVmZmVjdHMgbW9kZWxzLCBidXQgSSB0aGluayB0aGlzIGNhbiBoZWxwIHlvdSB1bmRlcnN0YW5kIHdoYXQgbWl4ZWQgZWZmZWN0cyBtb2RlbHMgYXJlIGRvaW5nLgoKV2hpbGUgdGhlIG5vLXBvb2xpbmcgYXBwcm9hY2ggdG8gbW9kZWxsaW5nIGlzbid0IHRoZSBtb3N0IHNvcGhpc3RpY2F0ZWQgKGFuZCB5b3UgZGVmaW5pdGVseSBjYW4ndCB1c2UgdGhlaXIgcC12YWx1ZXMpLCBJIHRoaW5rIGl0IGlzIG9mdGVuIFthIGdvb2QgaWRlYSB0byB0cnkgaXQgb3V0IGFzIGFuIGV4cGxvcmF0b3J5IHRlY2huaXF1ZV0oaHR0cDovL2pvZnJod2xkLmdpdGh1Yi5pby9ibG9nLzIwMTYvMDUvMDEvbWFueV9tb2RlbHMuaHRtbCkuICBZb3UgY2FuIGNoZWNrIG91dCBbYSB0YWxrIGJ5IEhhZGxleSBXaWNraGFtIGFib3V0IGl0IGhlcmVdKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9cnozX0ZEVnQ5ZWcpLiAKCgpJdCBpcyBwcmV0dHkgZWFzeSB0byBmaXQgb25lIG1vZGVsIGZvciBvbmUgc3BlYWtlci4KV2UganVzdCB0YWtlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIGFuZCBmaXQgdGhlIG1vZGVsOgoKCmBgYHtyfQpzcGVha2VycyA8LSB1bmlxdWUoYXlUJGlkc3RyaW5nKQoKc3AxIDwtIGF5VCAlPiUKICAgICAgICAgIGZpbHRlcihpZHN0cmluZyA9PSBzcGVha2Vyc1sxXSkKc3AxX21vZCA8LSBsbShGMV9uIH4gZHVyX2MsIGRhdGEgPSBzcDEpCnN1bW1hcnkoc3AxX21vZCkKYGBgCgpUaGVyZSBpcyBldmVuIGEgaGFuZHkgZGFuZHkgZnVuY3Rpb24gaW4gdGhlIGBicm9vbWAgcGFja2FnZSBjYWxsZWQgYHRpZHkoKWAgdGhhdCB3aWxsIGNvbnZlcnQgYSBsaW5lYXIgbW9kZWwgb2JqZWN0IChhbmQgbWFueSBvdGhlcnMpIGludG8gYSBkYXRhIGZyYW1lLgoKYGBge3J9CnRpZHkoc3AxX21vZCkKYGBgCgpCdXQgdGhlcmUgYXJlIGByIGxlbmd0aCh1bmlxdWUoYXlUJGlkc3RyaW5nKSlgIHNwZWFrZXJzIGluIHRoaXMgZGF0YSBzZXQuCldlIGNhbid0IGdvIHJlcGVhdGluZyB0aGlzIHByb2NlZHVyZSB0aGF0IG1hbnkgdGltZXMuIApJIHdpbGwgYmUgdXNpbmcgdG9vbHMgZnJvbSB0aGUgdGlkeXZlcnNlIHRvIGZpdCBvbmUgbW9kZWwgZm9yIGVhY2ggc3BlYWtlciwgYW5kIGNvbWJpbmUgdGhlbSBhbGwgdG9nZXRoZXIuIApUaGUgZXhhY3QgZGV0YWlscyBvZiBob3cgdGhpcyB3b3JrcyBnb2VzIGEgYml0IGJleW9uZCB3aGF0IHdlIGhhdmUgdGltZSB0byBjb3ZlciBoZXJlIHRvZGF5LCBidXQgaWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGhvdyBpdCB3b3JrcyB5b3UgY2FuIGRvd25sb2FkIHRoZSBzb3VyY2UgY29kZSBmb3IgdGhpcyBsZWN0dXJlIGZyb20gdGhlIGBDb2RlYCB0YWIgYXQgdGhlIHRvcCBvZiB0aGUgcGFnZS4gCgpUaGUgcmVzdWx0cyBvZiB0aGUgbm8tcG9vbGluZyBtb2RlbCBpcyBwbG90dGVkIGJlbG93LgpGb3IgZXZlcnkgc3BlYWtlciwgSSd2ZSBwbG90dGVkIHRoZWlyIGVzdGltYXRlZCBpbnRlcmNlcHQgYWxvbmcgdGhlIHgtYXhpcyBhbmQgdGhlaXIgZXN0aW1hdGVkIHNsb3BlIGFsb25nIHRoZSB5LWF4aXMuCgpgYGB7ciBlY2hvID0gRn0KIyBXZWxjb21lLCB0cmF2ZWxlcnMuLi4KIyBzZWUgYWxzbyBteSBub3RlcyBvbiBTcGxpdC1BcHBseS1Db21iaW5lIGh0dHA6Ly9qb2ZyaHdsZC5naXRodWIuaW8vdGVhY2hpbmcvY291cnNlcy8yMDE3X2xzYS9sZWN0dXJlcy9TZXNzaW9uXzMubmIuaHRtbAojIGFuZCBteSBsb25nZXIgZGlzY3Vzc2lvbiBvZiB0aGlzIHNlY3Rpb24gb2Ygbm90ZXM6IGh0dHA6Ly9qb2ZyaHdsZC5naXRodWIuaW8vdGVhY2hpbmcvY291cnNlcy8yMDE3X2xzYS9sZWN0dXJlcy9TZXNzaW9uXzcubmIuaHRtbCNmaXR0aW5nX25vLXBvb2xpbmdfbW9kZWxzCgoKYXlUICU+JSAKICBncm91cF9ieShpZHN0cmluZyklPiUKICBuZXN0KCklPiUKICBtdXRhdGUobW9kZWwgPSBtYXAoZGF0YSwgfmxtKEYxX24gfiBkdXJfYywgZGF0YSA9IC54KSksCiAgICAgICAgIHBhcmFtcyA9IG1hcChtb2RlbCwgdGlkeSksCiAgICAgICAgIG4gPSBtYXAoZGF0YSwgbnJvdykgJT4lIHNpbXBsaWZ5KCkpJT4lCiAgdW5uZXN0KHBhcmFtcyklPiUKICBzZWxlY3QoaWRzdHJpbmcsIHRlcm0sIGVzdGltYXRlLCBuKSU+JQogIHNwcmVhZCh0ZXJtLCBlc3RpbWF0ZSkgLT4gcGFyYW1zCgpgYGAKCmBgYHtyIGVjaG8gPSBGfQpwYXJhbXMgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShkdXJfYykpJT4lCiAgZ2dwbG90KGFlcyhgKEludGVyY2VwdClgLCBkdXJfYykpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JleTUwIikrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmV5NTAiKSsKICAgIGdlb21fcG9pbnQoYWVzKHNpemUgPSBuKSwgYWxwaGEgPSAwLjYpKwogICAgc2NhbGVfc2l6ZV9hcmVhKCkrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICBjb29yZF9maXhlZCgpCmBgYAoKClRoaXMgbm8tcG9vbGluZyBhcHByb2FjaCBpcyBpbmZvcm1hdGl2ZSwgYnV0IGFsc28gaGFzIHNvbWUgc2VyaW91cyB3ZWFrbmVzc2VzLgpGaXJzdCBvZiBhbGwsIHdlIGNhbiBzZWUgdGhhdCAqbW9zdCogc3BlYWtlcnMgaGF2ZSB0aGUgZXhwZWN0ZWQgc2xvcGUgKG9uIHRoZSB5LWF4aXMpIGJldHdlZW4gZHVyYXRpb24gYW5kIEYxLiAKVGhhdCBpcywgdGhlIHNsb3BlIGlzIHBvc2l0aXZlLCBtZWFuaW5nIGFzIGR1cmF0aW9uIGluY3JlYXNlcywgRjEgaW5jcmVhc2VzIChsb3dlcmluZyB0aGUgdm93ZWwpLgpIb3dldmVyLCB0aGVyZSBpcyBhIGxvdCBpZiBpbnRlci1zcGVha2VyIHZhcmlhYmlsaXR5LgpTb21lIHNwZWFrZXJzIGFyZSBlc3RpbWF0ZWQgdG8gaGF2ZSBhIGZhaXJseSBzdGVlcCBzbG9wZSwgYW5kIG90aGVycyBoYXZlIHNsb3BlcyBjbG9zZXIgdG8gMCBvciBldmVuIG5lZ2F0aXZlLgoKSGVyZSdzIGEgcGxvdCBvZiB0aGUgYWN0dWFsIGxpbmVzIHRoZXNlIHBhcmFtZXRlcnMgY29ycmVzcG9uZCB0by4KCmBgYHtyfQpwYXJhbXMgJT4lCiAgZmlsdGVyKGlzLmZpbml0ZShkdXJfYykpJT4lCiAgZ2dwbG90KCkrCiAgICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0ID0gYChJbnRlcmNlcHQpYCwgCiAgICAgICAgICAgICAgICAgICAgc2xvcGUgPSBkdXJfYyksCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkrCiAgICB4bGltKC0xLCAyLjg1KSsKICAgIHhsYWIoImR1cl9jIikrCiAgICB5bGltKC0yLjE0LDUuOSkrCiAgICB5bGFiKCJGMV9uIikrCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcyA9ICJiaWctbGFiZWwiPkRpc2N1c3Npb248L3NwYW4+CgpXaGF0IGFyZSB0aGUgcHJvcyBhbmQgY29ucyBvZiB0aGlzIG5vLXBvb2xpbmcgbW9kZWw/CjwvZGl2PgoKCiMgUGFydGlhbCBQb29saW5nIChNaXhlZCBFZmZlY3RzKQoKVGhlIGJpZ2dlc3QgZG93bnNpZGUgdG8gdGhlIG5vIHBvb2xpbmcgYXBwcm9hY2ggaXMgdGhhdCB0aGVyZSBpcyBubyBzaGFyZWQgaW5mb3JtYXRpb24gKmJldHdlZW4qIHRoZSBtb2RlbHMuIEl0J3MgcG9zc2libGUgdGhhdCBzcGVha2VycyB3aG8gaGFkIGEgbmVnYXRpdmUgc2xvcGUgd2VyZSBvbmx5IGVzdGltYXRlZCB0byBoYXZlIGEgbmVnYXRpdmUgc2xvcGUgYmVjYXVzZSB0aGV5IGhhZCB2ZXJ5IGxpdHRsZSBkYXRhLgpJZiB0aGVyZSB3ZXJlIHNvbWUgd2F5IHRvIGluY29ycG9yYXRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzbG9wZXMgb2YgZXZlcnkgb3RoZXIgc3BlYWtlciBpbnRvIHRoZXNlIHNwZWFrZXJzJyBzbG9wZSBlc3RpbWF0ZXMsIHRoZXkgbWlnaHQgYmUgY29uc2lkZXJhYmx5IGRpZmZlcmVudC4KClRoaXMgaXMgZXhhY3RseSB3aGF0IE1peGVkIEVmZmVjdHMgTW9kZWxzIGRvLiBZb3UgZGVmaW5lICJncm91cGluZyB2YXJpYWJsZXMiIG9yICJwb29saW5nIHZhcmlhYmxlcyIgb3IgInJhbmRvbSBlZmZlY3RzIiBpbiB0aGUgbW9kZWwgdG8gdGVsbCB0aGUgbW9kZWwgdG8gZXN0aW1hdGUgZWZmZWN0cyBmb3IgZWFjaCBzcGVha2VyLCBidXQgbm90IHRvIGRvIHNvIGNvbXBsZXRlbHkgaW5kZXBlbmRlbnRseSBmb3IgZWFjaCBzcGVha2VyLgoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcyA9ICdiaWctbGFiZWwnPn4yIE1pbnV0ZSBBY3Rpdml0eTwvc3Bhbj4KCkZpdCBhIGNvbXBsZXRlIHBvb2xpbmcgbW9kZWwgd2l0aCBgbG1gIGFuZCBhIHBhcnRpYWwgcG9vbGluZyBtb2RlbCB3aXRoIGBsbWVyYCB3aXRoIHRoZSBmb2xsb3dpbmcgY29kZS4KCmBgYHtyfQpheVRfbG0gPC1sbShGMV9uIH4gZHVyX2MsIGRhdGEgPSBheVQpCmF5VF9sbWUgPC0gbG1lcihGMV9uIH4gZHVyX2MgKyAoMSArIGR1cl9jIHwgaWRzdHJpbmcpLCBkYXRhID0gYXlUKQpgYGAKCjwvZGl2PgoKVGhlIGJpZyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGNvbXBsZXRlIHBvb2xpbmcgYW5kIHRoZSBwYXJ0aWFsIHBvb2xpbmcgbW9kZWxzIGFyZSB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgInJhbmRvbSBlZmZlY3RzIiBzdHJ1Y3R1cmVzLiAKCjxkaXYgY2xhc3MgPSAiaWxsdXN0cmF0ZSI+Cig8c3BhbiBjbGFzcyA9ICJwb3AiPjE8L3NwYW4+ICsgPHNwYW4gY2xhc3MgPSAicG9wIj5kdXJfYzwvc3Bhbj4gfCA8c3BhbiBjbGFzcyA9ICJwb3AiPmlkc3RyaW5nPC9zcGFuPikKPC9kaXY+CgotIEV2ZXJ5dGhpbmcgdG8gdGhlIGxlZnQgb2YgdGhlIGB8YAogICAgLSBFdmVyeXRoaW5nIHRoYXQgY2FuIHZhcnkgd2l0aGluIHRoZSBncm91cGluZyB2YXJpYWJsZS4gCiAgICAtIGAxYCByZWZlcnMgdG8gdGhlIGludGVyY2VwdAotIEV2ZXJ5dGhpbmcgdG8gdGhlIHJpZ2h0IG9mIHRoZSBgfGAKICAgIC0gVGhlIGdyb3VwaW5nIHZhcmlhYmxlLgogICAgCldpdGggYCgxICsgZHVyX2MgfCBpZHN0cmluZyApYCwgd2UncmUgc2F5aW5nCgo+IFNwZWFrZXJzIGNhbiBoYXZlIHZhcmlhYmxlIGludGVyY2VwdHMsIGFuZCB2YXJpYWJsZSBzbG9wZXMuCgpMZXQncyBsb29rIGF0IHRoZSBzdW1tYXJ5IG9mIHRoZSBtaXhlZCBlZmZlY3RzIG1vZGVsLgoKYGBge3J9CnN1bW1hcnkoYXlUX2xtZSkKYGBgCgoKIyMgVGhlICJSYW5kb20gRWZmZWN0cyIKCjxkaXYgY2xhc3MgPSAnaGFsZi1pbWcnPgoKIVtdKGZpZ3VyZXMvcmFuZWYucG5nKQo8L2Rpdj4KClN0cmljdGx5IHNwZWFraW5nLCB0aGUgbWl4ZWQgZWZmZWN0cyBtb2RlbHMgYXJlbid0IGVzdGltYXRpbmcgdGhlIGFjdHVhbCBzcGVha2VyLWxldmVsIHNsb3BlcyBhbmQgaW50ZXJjZXB0cyBhcyBwcm9wZXIgcGFyYW1ldGVycyBvZiB0aGUgbW9kZWwuCkluc3RlYWQsIGl0J3MgZXN0aW1hdGluZyB0aGUgKmNvdmFyaWFuY2UgbWF0cml4KiBvZiB0aGUgc2xvcGVzIGFuZCB0aGUgaW50ZXJjZXB0cy4KSW4gdGhpcyBzdW1tYXJ5IGl0J3Mgc2hvd2luZyB1cwoKLSBUaGUgdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBpbmRpdmlkdWFsIGxldmVsIGludGVyY2VwdHMuCi0gVGhlIHZhcmlhbmNlIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgaW5kaXZpZHVhbCBsZXZlbCBzbG9wZXMuCi0gVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGludGVyY2VwdHMgYW5kIHNsb3Blcy4KLSBUaGUgdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgcmVtYWluaW5nIHJlc2lkdWFscy4KCkhlcmUsIGl0IGxvb2tzIGxpa2Ugc3BlYWtlcnMgYXJlIG1vcmUgdmFyaWFibGUgd2l0aCByZXNwZWN0IHRvIHRoZWlyIGJhc2VsaW5lIEYxIHRoYW4gdGhleSBhcmUgd2l0aCByZXNwZWN0IHRvIHRoZSBlZmZlY3QgZHVyYXRpb24gaGFzIG9uIHRoZWlyIEYxLgpBbmQsIHRoZSAqbGFyZ2VyKiBhIHNwZWFrZXJzJyBiYXNlbGluZSBGMSBpcywgdGhlaXIgZWZmZWN0IG9mIGR1cmF0aW9uIGlzIHNvbWV3aGF0IHdlYWtlciwgYnV0IGl0J3Mgbm90IGEgdmVyeSBzdHJvbmcgY29ycmVsYXRpb24uCgojIyBGaXhlZCBFZmZlY3RzCgo8ZGl2IGNsYXNzID0gJ2hhbGYtaW1nJz4KIVtdKGZpZ3VyZXMvZml4ZWYucG5nKQo8L2Rpdj4KCgpUaGVzZSBhcmUgdGhlIGVzdGltYXRlZCAiZml4ZWQgZWZmZWN0Ii4gVGhleSBjYW4gYmUgaW50ZXJwcmV0ZWQgYSBsb3QgbGlrZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBtb2RlbHMgd2UndmUgYmVlbiBmaXR0aW5nIGFscmVhZHksIGluIHRoZSBzZW5zZSB0aGF0IHRoZXNlIGFyZSBwYXJ0IG9mIHRoZSBmb3JtdWxhIHRvIGRyYXcgYSBsaW5lLiBBbm90aGVyIHdheSBpcyB0byBpbnRlcnByZXQgdGhlc2UgYXMgdGhlICphdmVyYWdlKiBpbnRlcmNlcHQgYW5kIHNsb3BlIGJldHdlZW4gc3BlYWtlcnMuCgojIyBMb29raW5nIGF0IHRoZSByYW5kb20gZWZmZWN0cwoKSXQgaXMgcG9zc2libGUgdG8gZXh0cmFjdCBlc3RpbWF0ZXMgb2YgdGhlbiByYW5kb20gZWZmZWN0cyB1c2luZyB0aGUgZnVuY3Rpb24gYHJhbmVmKClgLiBTdHJpY3RseSBzcGVha2luZywgdGhlc2UgYXJlICJCTFVQcyIsIHdoaWNoIGlzIHN0YW5kcyBmb3IgIkJlc3QgTGluZWFyIFVuYmlhc2VkIFByZWRpY3RvcnMiLiAKVGhlIHBvaW50IGhlcmUgaXMgdGhhdCB0aGVzZSBhcmVuJ3QgKnByb3BlciogcGFyYW1ldGVycyBvZiB0aGUgbW9kZWwsIGJ1dCB0aGUgZGlzdGluY3Rpb24gaGVyZSBpcyBhIGJpdCBhcmNhbmUgZm9yIGFuIGludHJvZHVjdG9yeSBjb3Vyc2UuCgpgYGB7cn0KaGVhZChyYW5lZihheVRfbG1lKSRpZHN0cmluZykKYGBgCgpUaGVzZSBhcmUgdGhlIHByZWRpY3RlZCBkaWZmZXJlbmNlcyBpbiBJbnRlcmNlcHQgYW5kIHNsb3BlIGZvciBlYWNoIHNwZWFrZXIgZnJvbSB0aGUgZml4ZWQgZWZmZWN0cy4gVGhhdCBpcywgaWYgd2UgYWRkZWQgdGhlIGAoSW50ZXJjZXB0KWAgdmFsdWUgZnJvbSB0aGUgZml4ZWQgZWZmZWN0cyB0byB0aGVzZSByYW5kb20gZWZmZWN0cywgd2Ugd291bGQgZ2V0IHRoZSBwcmVkaWN0ZWQgc2xvcGUgZm9yIGVhY2ggc3BlYWtlci4gTGV0J3MgZG8gdGhhdDoKCmBgYHtyIGVjaHAgPSBGfQpheVRfbG1lX2ZpeGVmIDwtIGZpeGVmKGF5VF9sbWUpCgpyYW5lZihheVRfbG1lKSRpZHN0cmluZyAlPiUKICBnZ3Bsb3QoYWVzKGAoSW50ZXJjZXB0KWAgKyBheVRfbG1lX2ZpeGVmWzFdLCAKICAgICAgICAgICAgIGR1cl9jICsgYXlUX2xtZV9maXhlZlsyXSkpKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrICAKICAgIHRoZW1lX21pbmltYWwoKSsKICAgIGNvb3JkX2ZpeGVkKCkKYGBgCgoKYGBge3IgZWNobyA9IEZ9CmF5VF9sbWVfZml4ZWYgPC0gZml4ZWYoYXlUX2xtZSkKCnJhbmVmKGF5VF9sbWUpJGlkc3RyaW5nICU+JQogIGdncGxvdCgpKwogICAgICAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IGAoSW50ZXJjZXB0KWAgKyBheVRfbG1lX2ZpeGVmWzFdLCAKICAgICAgICAgICAgICAgICAgICBzbG9wZSA9IGR1cl9jICsgYXlUX2xtZV9maXhlZlsyXSksCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkrCiAgICB4bGltKC0xLCAyLjg1KSsKICAgIHhsYWIoImR1cl9jIikrCiAgICB5bGltKC0yLjE0LDUuOSkrCiAgICB5bGFiKCJGMV9uIikrCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgpXZSBjYW4gZ2V0IGFuIGlkZWEgb2Ygd2hhdCB0aGUgbWl4ZWQtZWZmZWN0cyBtb2RlbGxpbmcgaGFzIGRvbmUgYnkgY29tcGFyaW5nIHRoZXNlIHJlc3VsdHMgdG8gdGhlIG5vLXBvb2xpbmcgbW9kZWwuIApGaXJzdCwgdGhlIGNsdXN0ZXJpbmcgb2YgaW5kaXZpZHVhbCBzcGVha2VycycgcmFuZG9tIGVmZmVjdHMgaXMgdGlnaHRlci4gCkFsc28sIG5vIHNwZWFrZXIgaXMgZXN0aW1hdGVkIHRvIGhhdmUgYW4gaW5kaXZpZHVhbCBzbG9wZSBsZXNzIHRoYW4gMC4gCgpJdCBpcyBhbHNvIHBvc3NpYmxlIHRvIHNlZSB0aGUgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmFuZG9tIGVmZmVjdHMuClNwZWFrZXJzIHdobyBoYXZlIGEgYmFzZWxpbmUgbG93ZXIgYGF5VGAgYXBwZWFyIHRvIGJlIG1vcmUgYWZmZWN0ZWQgYnkgZHVyYXRpb24gY2hhbmdlcy4KCgojIyBNdWx0aXBsZSByYW5kb20gZWZmZWN0cwoKVGhpcyBpcyB3aGVyZSBpdCBnZXRzIGltcG9zc2libGUgdG8gbWFrZSBpbGx1c3RyYXRpdmUgZ3JhcGhzLgpJdCBpcyBhbHNvIHBvc3NpYmxlIHRvIGluY2x1ZGUgbXVsdGlwbGUgZ3JvdXBpbmcgZmFjdG9ycyBpbiBhIG1peGVkIGVmZmVjdHMgbW9kZWwuCgo8ZGl2IGNsYXNzID0gJ2JyZWFrIGJveCc+CjxzcGFuIGNsYXNzID0gJ2JpZy1sYWJlbCc+fjUgbWludXRlIGJyZWFrPC9zcGFuPgoKV2UncmUgZ29pbmcgdG8gYWRkIGB3b3JkYCBhcyBhIGdyb3VwaW5nIGZhY3Rvci4gRm9yIG5vdywgd2UnbGwgdHJlYXQgYHdvcmRgIGFzIG9ubHkgYmVpbmcgYWJsZSB0byBtb2R1bGF0ZSB0aGUgYmFzZWxpbmUgYEYxX25gLCB3aGljaCBtZWFucyB3ZSdsbCBhZGQgaXQgd2l0aCBgKDEgfCB3b3JkKWAgKGEuay5hLiBhIHJhbmRvbSBpbnRlcmNlcHQpLgoKR28gYWhlYWQgYW5kIGZpdCB0aGlzIG1vZGVsOgoKYGBge3J9CmF5VF9sbWVfbXVsdGkgPC0gbG1lcihGMV9uIH4gZHVyX2MgKyAKICAgICAgICAgICAgICAgICAgICAgICAoMSArIGR1cl9jIHwgaWRzdHJpbmcpICsgCiAgICAgICAgICAgICAgICAgICAgICAgKDEgfCB3b3JkKSwgZGF0YSA9IGF5VCkKc3VtbWFyeShheVRfbG1lX211bHRpKQpgYGAKCldoYXQgaGFwcGVuZWQ/Cgo8L2Rpdj4KCgpIb3dldmVyLCBpdCBpcyAqcG9zc2libGUqIHRvIGluY2x1ZGUgYSByYW5kb20gc2xvcGUgYnkgd29yZCB0b28sIHNvIGxldCdzIGRvIHRoYXQgYXMgd2VsbDoKCmBgYHtyfQpheVRfbG1lX211bHRpMiA8LSBheVRfbG1lX211bHRpIDwtIGxtZXIoRjFfbiB+IGR1cl9jICsgCiAgICAgICAgICAgICAgICAgICAgICAgKDEgKyBkdXJfYyB8IGlkc3RyaW5nKSArIAogICAgICAgICAgICAgICAgICAgICAgICgxICsgZHVyX2N8IHdvcmQpLCBkYXRhID0gYXlUKQpzdW1tYXJ5KGF5VF9sbWVfbXVsdGkyKQpgYGAKCk9uZSB0aGluZyB5b3UgbWlnaHQgbm90aWNlIG5vdyBpcyB0aGF0IHRoZSAiZml4ZWQgZWZmZWN0IiBvZiBkdXJhdGlvbiBoYXMgZ290dGVuIGEgYml0IHNtYWxsZXIuIAoKCmBgYHtyfQojIGNvbXBsZXRlIHBvb2xpbmcKY29lZihheVRfbG0pCmBgYAoKYGBge3J9CiMgZnVsbCByYW5lZiBzdHJ1Y3R1cmUKZml4ZWYoYXlUX2xtZV9tdWx0aTIpCmBgYAoKCgoKVGhpcyBtYXkgbG9vayBzY2FyeSwgZXNwZWNpYWxseSBpZiB0aGUgZWZmZWN0IHNpemUgZ3JhZHVhbGx5IHZhbmlzaGVzIGF3YXksIGJ1dCB0aGlzIGlzIGV4YWN0bHkgaG93IG1peGVkIGVmZmVjdHMgbW9kZWxzIGFyZSBzdXBwb3NlZCB0byB3b3JrLiAKSW4gc29tZSBzZW5zZSwgaW4gdGhlIGNvbXBsZXRlLXBvb2xpbmcgbW9kZWwsIHdlICp0aG91Z2h0KiB3ZSB3ZXJlIG1vZGVsbGluZyB0aGUgZWZmZWN0IG9mIGR1cmF0aW9uLCBidXQgYWN0dWFsbHkgc29tZSBvZiB0aGF0IGVmZmVjdCB3YXMgYWN0dWFsbHkgZHVlIHRvIHRoZSBwZWN1bGlhcml0aWVzIG9mIHRoZSB3b3JkcyBzcG9rZW4sIGFuZCB3aG8gdGhlIHNwZWFrZXJzIHdlcmUuCgoKIyMgV2hlbiB0byBhZGQgcmFuZG9tIGludGVyY2VwdHMvc2xvcGVzPwoKW0JhcnIgZXQgYWwgKDIwMTIpXShodHRwOi8vaWRpb20udWNzZC5lZHUvfnJsZXZ5L3BhcGVycy9iYXJyLWV0YWwtMjAxMy1qbWwucGRmKSByZWNvbW1lbmQgKGNvbW1hbmQ/KSBmaXR0aW5nIG1vZGVscyAgd2l0aCAibWF4aW1hbCIgcmFuZG9tIGVmZmVjdHMgc3RydWN0dXJlcy4KVGhhdCBpcywgZm9yIGV2ZXJ5IHBvc3NpYmxlIGdyb3VwaW5nIGZhY3RvciwgaW5jbHVkZSBhIHJhbmRvbSBzbG9wZSBmb3IgZXZlcnkgZ3JvdXBpbmcgZmFjdG9yIHRoYXQncyBsb2dpY2FsbHkgcG9zc2libGUuCkkgdGhpbmsgdGhpcyBpcyBhIGdvb2Qgc3RhcnRpbmcgcG9pbnQsIGJ1dCBpc24ndCBhbHdheXMgcHJhY3RpY2FsLgoKIyMjIExvZ2ljYWxseSBQb3NzaWJsZSAmIEltcG9zc2libGUgUmFuZG9tIFNsb3BlcwoKSW4gdGhlIGBheVRgIG1vZGVsIHdlIGp1c3QgZml0LCBpdCB3YXMgcG9zc2libGUgZm9yIHVzIHRvIGZpdCBhIHJhbmRvbSBzbG9wZSBvZiBkdXJhdGlvbiBieSBzcGVha2VyIGFuZCB3b3JkLCBiZWNhdXNlIHNwZWFrZXJzIHByb2R1Y2VkIHRva2VucyB3aXRoIGRpZmZlcmVudCBkdXJhdGlvbiwgYW5kIHdvcmRzIHdlcmUgcHJvZHVjZWQgd2l0aCBkaWZmZXJlbnQgZHVyYXRpb25zLgoKSG93ZXZlciwgaWYgd2Ugd2FudGVkIHRvIGluY2x1ZGUgYHZvaWNpbmdgIGFnYWluIChwcmUtdm9pY2VsZXNzIHZzIGVsc2V3aGVyZSksIHdlIGNvdWxkIGluY2x1ZGUgYSByYW5kb20gc2xvcGUgb2Ygdm9pY2luZyBieSBzcGVha2VyLCBidXQgKm5vdCogYnkgd29yZC4KVGhpcyBpc24ndCBhIHByb2hpYml0aW9uLCBpdCdzIGp1c3Qgbm90IGxvZ2ljYWxseSBwb3NzaWJsZSBhbmQgbWlnaHQgYmxvdyB1cCB5b3VyIG1vZGVsLgpUaGF0J3MgYmVjYXVzZSBlYWNoIHdvcmQgb25seSBldmVyeSBoYXMgb25lIHZvaWNpbmcgY29udGV4dC4KSW4gdGhlIHdvcmQsIGBOSUNFYCwgdGhlIGZvbGxvd2luZyAvcy8gaXMgdm9pY2VsZXNzLCBhbmQgYWx3YXlzIHdpbGwgYmUuCgpTaW1pbGFybHksIGlmIHdlIHdhbnRlZCB0byBpbmNsdWRlIHllYXIgb2YgYmlydGggaW4gdGhlIG1vZGVsLCB3ZSBjb3VsZCBpbmNsdWRlIGEgcmFuZG9tIHNsb3BlIG9mIGRvYiBieSB3b3JkLCBiZWNhdXNlIG1hbnkgd29yZHMgd2VyZSBzcG9rZW4gYnkgcGVvcGxlIGFjcm9zcyBtYW55IGFnZXMuIEJ1dCB3ZSAqY291bGRuJ3QqIGluY2x1ZGUgYSByYW5kb20gc2xvcGUgb2YgZG9iIGJ5IHNwZWFrZXIsIGJlY2F1c2UgZWFjaCBzcGVha2VyIG9ubHkgaGFzIG9uZSBkYXRlIG9mIGJpcnRoLgoKCiMjIyBOZWNlc3NhcnkgUmFuZG9tIEVmZmVjdHMKCkFueSB0aW1lIHlvdSBhcmUgbG9va2luZyBhdCBhIGJldHdlZW4tZ3JvdXBpbmcgZmFjdG9yIHZhcmlhYmxlLCB5b3Ugc2hvdWxkIGluY2x1ZGUgdGhlIGdyb3VwaW5nIGZhY3RvciB3aXRoIGEgcmFuZG9tIGludGVyY2VwdC4gVGhpcyBpcyAqZXNwZWNpYWxseSogdHJ1ZSBmb3IgYW55IGtpbmQgb2YgcmVzZWFyY2ggZG9uZSBvdXRzaWRlIG9mIGFuIGV4cGVyaW1lbnRhbCBsYWIgY29udGV4dC4KCi0gYWdlOiBgKDEgfCBzcGVha2VyKWAKLSBnZW5kZXI6IGAoMSB8IHNwZWFrZXIpYAotIHdvcmQgZnJlcXVlbmN5OiBgKDEgfCB3b3JkKWAKLSBzZW50ZW5jZSBncmFtbWF0aWNhbGl0eTogYCgxIHwgdG9rZW4pYAoKT3RoZXIgbmVjZXNzYXJ5IHJhbmRvbSBlZmZlY3RzIHdvdWxkIGJlIHJlbGF0ZWQgdG8gdGhlIG5hdHVyZSBvZiB0aGUgZGF0YS4gSW4gdGhpcyBgYWhgIG1vZGVsLCB3ZSBoYXZlbid0IGV4cGxvcmVkIGFueSBiZXR3ZWVuLWdyb3VwaW5nIGZhY3RvcnMsIGJ1dCBhbGwgb2YgdGhlc2UgZGF0YSBwb2ludHMgd2VyZSBwcm9kdWNlZCBieSBzcGVha2VycywgZW1iZWRkZWQgaW4gc3BlY2lmaWMgd29yZHMsIHNvIGl0J3MgaW1wb3J0YW50IHRvIGNhcHR1cmUgdGhhdCBpbiB0aGUgcmFuZG9tIGVmZmVjdHMuCgojIyMgUmVjb21tZW5kZWQgUmFuZG9tIEVmZmVjdHMKCkl0IGlzIGEgZ29vZCBpZGVhIHRvIGluY2x1ZGUgeW91ciBiaWdnZXN0IGVmZmVjdHMsIG9yIGVmZmVjdHMgb2YgZ3JlYXRlc3QgaW50ZXJlc3QsIGFzIHJhbmRvbSBzbG9wZXMgYWNyb3NzIHRoZSBncm91cGluZyBmYWN0b3JzIHdoaWNoIGNvbnRhaW4gdGhlIG1vc3QgZGF0YS4KCgojIFRoZSBhc3N1bXB0aW9ucyBvZiBMTUVzCgpUaGUgd2F5IExNRXMgd29yayBpcyB0aGV5IG1ha2Ugc29tZSBzdHJvbmcgYXNzdW1wdGlvbnMgYWJ1dCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSByYW5kb20gZWZmZWN0cy4gTGV0J3MgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwYXJhbWV0ZXJzIGZyb20gdGhlIG5vLXBvb2xpbmcgbW9kZWwgYWdhaW4gKGkuZS4gd2hlbiB3ZSBmaXQgMSBtb2RlbCBmb3IgZWFjaCBzcGVha2VyKS4KCmBgYHtyIGVjaG8gPSBGfQpwYXJhbXMgJT4lCiAgZ2F0aGVyKHBhcmFtLCBlc3QsIGAoSW50ZXJjZXB0KWA6ZHVyX2MpLT5wYXJhbV9sb25nCnBhcmFtX2xvbmcgJT4lIAogIGdncGxvdChhZXMoZXN0KSkrCiAgICBzdGF0X2RlbnNpdHkoYWxwaGEgPSAwLjgsIGNvbG9yID0gImJsYWNrIikrCiAgICBmYWNldF93cmFwKH5wYXJhbSwgc2NhbGVzID0gImZyZWUiKSsKICAgIHhsYWIoImVzdGltYXRlIikrCiAgICB0aGVtZV9idygpCmBgYAoKVGhlc2UgYnktc3BlYWtlciBwYXJhbWV0ZXJzIHdlcmUgZXN0aW1hdGVkIHZpYSAqbWF4aW11bSBsaWtlbGlob29kKi4KVGhhdCBpcywgdGhlc2UgYXJlIHRoZSBlc3RpbWF0ZWQgc2xvcGVzIGFuZCBpbnRlcmNlcHRzIHRoYXQgYmVzdCBzYXRpc2Z5IHRoZSBsaW5lYXIgcmVncmVzc2lvbiBmb3JtdWxhLgoKVGhlIHJhbmRvbSBpbnRlcmNlcHRzIGFuZCBzbG9wZXMgYXJlICpub3QqIGVzdGltYXRlZCBpbiB0aGlzIHdheS4KUmF0aGVyLCB0aGUgbW9kZWwgYXNzdW1lcyB0aGF0IHRoZSByYW5kb20gaW50ZXJjZXB0cyBhbmQgc2xvcGVzIGFyZSBkcmF3biBmcm9tIGEgKm5vcm1hbCBkaXN0cmlidXRpb24qLiAKVGhhdCBpcywgdGhlIHJhbmdlIG9mIG9mIHBvc3NpYmxlIHJhbmRvbSBpbnRlcmNlcHRzIGFuZCBzbG9wZXMgYXJlICpjb25zdHJhaW5lZCosIHNvIHRoYXQgdGhleSBhcmUgY29uc2lzdGVudCB3aXRoIGJlaW5nIGRyYXduIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uLgpUaGlzIGlzIHdoYXQgYWxsb3dzIHRoZSBlc3RpbWF0ZXMgZm9yIGVhY2ggc3BlYWtlciB0byBiZSAicGFydGlhbGx5IHBvb2xlZC4iCkV2ZW4gaWYgdGhlcmUgaXMgbm90IHZlcnkgbXVjaCBkYXRhIGZyb20gYSBzaW5nbGUgc3BlYWtlciwgd2UgY2FuIHN0aWxsIGdldCBzb21lIHNlbnNlIG9mIHdoYXQgdGhlaXIgaW5kaXZpZHVhbCBzbG9wZSBvdWdodCB0byBiZSBpZiB3ZSB3ZSBsb29rIGF0IHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNsb3BlcyBhY3Jvc3MgYWxsIHNwZWFrZXJzLgoKVGhpcyBhbHNvIGxlYWRzIHRvICJzaHJpbmthZ2UiIG9mIHRoZSBlc3RpbWF0ZWQgcmFuZG9tIGVmZmVjdHMuCkNvbXBhcmUgdGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXMgKGluIHllbGxvdykgdG8gdGhlIHJhbmRvbSBlZmZlY3RzIChpbiBncmV5KSBiZWxvdy4KRm9yIHRoZSByYW5kb20gc2xvcGUgZXNwZWNpYWxseSwgdGhlIHJhbmdlIG9mIHZhbHVlcyBpcyBtdWNoIG5hcnJvd2VyLgoKYGBge3IgZWNobyA9IEZ9CmxpYnJhcnkoZ2d0aGVtZXMpCnJhbmVmKGF5VF9sbWUpJGlkc3RyaW5nICU+JQogIG11dGF0ZShgKEludGVyY2VwdClgID0gYChJbnRlcmNlcHQpYCsgYXlUX2xtZV9maXhlZlsxXSwKICAgICAgICAgIGR1cl9jID0gZHVyX2MgKyBheVRfbG1lX2ZpeGVmWzJdLAogICAgICAgICBlc3RpbWF0b3IgPSAibG1lIiklPiUKICBnYXRoZXIocGFyYW0sIGVzdCwgYChJbnRlcmNlcHQpYDpkdXJfYyklPiUKICBiaW5kX3Jvd3MocGFyYW1fbG9uZyAlPiUgbXV0YXRlKGVzdGltYXRvciA9ICJtbCIpKSU+JQogIGdncGxvdChhZXMoZXN0KSkrCiAgICBnZW9tX2RlbnNpdHkoYWVzKGZpbGwgPSBlc3RpbWF0b3IpLCAKICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJpZGVudGl0eSIsCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjYpKwogICAgZmFjZXRfd3JhcCh+cGFyYW0sIHNjYWxlcz0iZnJlZSIpKwogICAgc2NhbGVfZmlsbF9jb2xvcmJsaW5kKCkrCiAgICB0aGVtZV9idygpCmBgYAoKQnkgYW5kIGxhcmdlLCB0aGlzIHNocmlua2FnZSBpcyBhIGdvb2QgdGhpbmcuCkxldCdzIHNheSB0aGF0IHlvdSByYW4gYSByZWFjdGlvbiB0aW1lIGV4cGVyaW1lbnQsIGFuZCB0aGVuIHRvb2sgeW91ciB0aHJlZSBzdWJqZWN0cyB3aG8gcHJlc3NlZCB0aGUgYnV0dG9uIHRoZSBmYXN0ZXN0IGFuZCB0aGUgdGhyZWUgc3ViamVjdHMgd2hvIHByZXNzZWQgdGhlIGJ1dHRvbiB0aGUgc2xvd2VzdCBhbmQgcmUtdGVzdGVkIHRoZW0uCkFsbW9zdCBpbnZhcmlhYmx5LCB0aGUgdGhyZWUgZmFzdGVzdCBzdWJqZWN0cyB3aWxsIGJlIGEgYml0IHNsb3dlciBvbiB0aGUgc2Vjb25kIHRlc3QsIGFuZCB0aGUgdGhyZWUgc2xvd2VzdCBhIGJpdCBmYXN0ZXIuClRoaXMgaXMgYWxzbyBrbm93biBhcyAicmVncmVzc2lvbiB0byB0aGUgbWVhbi4iIApZb3UgY291bGQgY29uc2lkZXIgdGhpcyBzaHJpbmthZ2Ugb2YgdGhlIHJhbmRvbSBlZmZlY3RzIHRvIGJlICJiYWtpbmcgaW4iIHRoaXMgcGhlbm9tZW5vbi4KCiMgIk51aXNhbmNlIHZhcmlhYmxlcyIKCkFub3RoZXIgd2F5IHRvIHRoaW5rIGFib3V0IHJhbmRvbSBlZmZlY3RzIGlzIGFzICJudWlzYW5jZSB2YXJpYWJsZXMiLgpXaGVuIG1vZGVsbGluZyBzb21ldGhpbmcgYXMgY29tcGxleCBhcyB3aHkgcHJvbnVuY2lhdGlvbnMgY2hhbmdlLCB0aGVyZSBhcmUgYWx3YXlzIGdvaW5nIHRvIGJlIGZhY3RvcnMgbWlzc2luZyBmcm9tIG91ciBtb2RlbHMgZm9yIGEgdmFyaWV0eSBvZiByZWFzb25zLgoKLSB0aGVyZSBhcmUgdGhpbmdzIHdlIGtub3cgbWF0dGVyLCBidXQgZmFpbGVkIHRvIG1lYXN1cmUgdGhlbSBmb3Igc29tZSByZWFzb24uCi0gdGhlcmUgYXJlIHRoaW5ncyB3ZSBrbm93IG1hdHRlciwgYnV0IHdlIGRvbid0IGtub3cgKmhvdyogdG8gbWVhc3VyZSB0aGVtLgotIHRoZXJlIGFyZSB0aGluZ3MgdGhhdCBtYXkgbm90IGJlICptZWFzdXJlYWJsZSouCi0gdGhlcmUgYXJlIHRoaW5ncyB3ZSBkb24ndCByZWFsaXplIG1hdHRlci4KCklmIHdlIGRvbid0IGRvIG91ciBiZXN0IHRvIGFjY291bnQgZm9yIHRoZXNlICJ1bm1vZGVsbGFibGVzIiwgdGhleSBjb3VsZCB2ZXJ5IHdlbGwgbWVzcyB3aXRoIG91ciBmaXhlZCBlZmZlY3RzIGVzdGltYXRlcy4gCldoaWxlIHRoZXkgYXJlIG5vdCBhIHBlcmZlY3Qgc29sdXRpb24sIHJhbmRvbSBlZmZlY3RzIGNhbiBnbyBzb21lIHdheSB0b3dhcmRzIHNvYWtpbmcgdXAgc29tZSBvZiB0aGVzZSB1bm1vZGVsYWJsZSB2YXJpYWJsZXMuCgpPbiB0aGUgZmxpcCBzaWRlLCBpZiB5b3UgaGF2ZSBzb21ldGhpbmcgeW91ICprbm93KiBoYXMgYW4gZWZmZWN0LCBpbmNsdWRlIGl0IGluIHRoZSBtb2RlbC4gCkZvciBleGFtcGxlLCB3ZSBrbm93IHRoYXQgZ2VuZGVyIGhhcyBhIGJpZyBlZmZlY3Qgb24gbWFueSBjaGFuZ2VzIGluIHByb2dyZXNzLgpZb3Ugc2hvdWxkLCB0aGVyZWZvcmUsIGluY2x1ZGUgaXQgaW4gdGhlIG1vZGVsIGluc3RlYWQgb2YgaG9waW5nIHRoYXQgdGhlIHJhbmRvbSBlZmZlY3RzIHdpbGwgYWNjb3VudCBmb3IgaXQuClRoYXQncyBiZWNhdXNlIGlmIHRoZXJlIGlzIGEgYmlnIGJldHdlZW4tc3ViamVjdCB2YXJpYWJsZSB0aGF0IGFmZmVjdHMgdGhlIG91dGNvbWUgdmFyaWFibGUsIHRoZSBhc3N1bXB0aW9uIHRoYXQgc3BlYWtlciByYW5kb20gaW50ZXJjZXB0cyAmIHNsb3BlcyBhcmUgZHJhd24gZnJvbSBhIHNpbmdsZSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIHZpb2xhdGVkLgoKCjxociAvPgoKCgoK